D - 转转的数据结构题
题意
有一个长度为 m m m的整数序列。初始所有元素都是 0 0 0。
有一个长度为 n n n的操作序列,每个操作形如 ( l , r , v ) (l,r,v) (l,r,v),表示将序列中的下标在 [ l , r ] [l,r] [l,r]的元素的值赋为 v v v。
有 q q q次询问,每次给出 x , y x,y x,y,表示只进行编号在 [ x , y ] [x,y] [x,y]的操作所得到的序列的所有元素的和。询问之间是独立的。
n , m , q ≤ 5 × 1 0 5 , v ≤ 1 0 9 n,m,q\le 5\times 10^5, v\le 10^9 n,m,q≤5×105,v≤109
Sol
如果依次进行所有的操作,每一次操作的时候覆盖掉的区间中,极长的由相同元素构成的区间的数量的和是 O ( n ) O(n) O(n)的。
考虑进行完前 y y y个操作时得到的序列,我们只需要知道这个序列中在第 x x x次操作以前就已经被赋值的元素的和,用现在的序列中元素的和减去它们就可以得到询问 x , y x,y x,y的答案。
依次进行所有操作,在维护所有极长的由相同元素构成的段的同时,维护插入时间小于等于每个 x x x的所有元素的和即可。
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#define PB push_back
#define PII pair<int,int>
#define MP make_pair
#define fir first
#define sec second
#define ll long long
using namespace std;
template <class T>
inline void rd(T &x) {
x=0; char c=getchar(); int f=1;
while(!isdigit(c)) {
if(c=='-') f=-1; c=getchar(); }
while(isdigit(c)) x=x*10-'0'+c,c=getchar(); x*=f;
}
const int N=5e5+10;
int n;
ll c[N];
void add(int i,ll t) {
for(;i;i-=i&-i) c[i]+=t; }
ll query(int i) {
ll ans=0; for(;i<=n;i+=i&-i) ans+=c[i]; return ans; }
struct seg {
int ty,p,t,v;
seg(int ty=0,int p=0,int t=0,int v=0): ty(ty),p(p),t(t),v(v) {
}
friend bool operator <(seg A,seg B) {
return A.p==B.p?A.ty>B.ty:A.p<B.p;
}
};
set<seg> s;
struct Que {
int l,r,v;
}Q[N];
vector<PII> U[N];
int m,q;
ll ans[N];
void del(seg A) {
add(A.t,-A.v*A.ty*(ll)A.p);
s.erase(A);
}
void add(seg A) {
add(A.t,A.v*A.ty*(ll)A.p);
s.insert(A);
}
vector<seg> D;
int main() {
rd(n),rd(m),rd(q);
for(int i=1;i<=n;++i) rd(Q[i].l),rd(Q[i].r),rd(Q[i].v);
for(int i=1,l,r;i<=q;++i) {
rd(l),rd(r);
U[r].PB(MP(l,i));
}
s.insert(seg(-1,1,0,0));
s.insert(seg(1,m+1,0,0));
for