题解:P11534 [NOISG 2023 Finals] Inspections
P11534 [NOISG 2023 Finals] Inspections
维护每个机器最后一次使用的时间,注意到每一次操作相当于将区间
修改区间的值考虑 ODT。不断修改区间,维护首项。
最棘手的问题就是如何计算答案。
由于答案只要求修改次数,不难想到在修改操作中,每次不断暴力修改块时顺便计算答案,开个 vector 存放前后两次差值和区间长度。最后将询问离线,从大到小顺序求解,将原来的 vector 中的区间一个个丢到询问中判断是否合法(有点类似于单调栈),如果不合法就调到下一个询问。由于我们将询问变得有序,故所求答案是单调不降的。我们就很顺利地解决了这个问题。
#define LL long long
#define IT set<node>::iterator
inline long long read() {
long long x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return x*f;
}
const int N = 2e5 + 10;
struct node {
int l, r;
mutable LL v;
node(int L, int R = -1, LL V = 0):l(L), r(R), v(V) {}
bool operator <(const node& b) const {
return l < b.l;
}
};
struct que {
LL s;
int id;
}a[N];
vector<pair<LL, LL> > d;
set<node>s;
IT split(int pos) {
IT it = s.lower_bound(pos);
if(it != s.end() && it->l == pos) return it;
--it;
int l = it->l, r = it->r;
LL v = it->v;
s.erase(it);
s.insert(node(l, pos - 1, v));
return s.insert(node(pos, r, v + pos - l)).first;
}
LL ans[N];
void assign(int l, int r, LL val) {
IT itr = split(r + 1), itl = split(l);
LL now = val;
for (IT it = itl; it != itr; it++) {
d.push_back(make_pair(now - it->v, it->r - it->l + 1));
now += it->r - it->l + 1;
}
s.erase(itl, itr);
s.insert(node(l, r, val));
}
bool cmp(que x, que y) {
return x.s > y.s;
}
void solve() {
int n = read(), m = read(), q = read();
s.insert(node(1ll, n, 1e18 + 10));
LL now = 1;
while(m--) {
int l = read(), r = read();
assign(l, r, now);
now += (LL)r - l + 1;
}
for (int i = 1; i <= q; i++) {
a[i].s = read(), a[i].id = i;
}
sort(a + 1, a + q + 1, cmp);
sort(d.begin(), d.end());
LL cnt = 0;
for (int i = 1; i <= q; i++) {
while(d.size() && d.back().first > a[i].s)
cnt += d.back().second, d.pop_back();
ans[a[i].id] = cnt;
}
for (int i = 1; i <= q; i++) cout << ans[i] << " ";
}