题目描述
分析
这道题把修改操作强制在线,但是查询却可以离线处理
对于每一个位置,我们开一棵权值线段树,记录这个位置上的每一个取值对答案的贡献
对于每一次询问,对它有贡献的点是区间([l,r])中大于等于(x)的数
因此我们考虑差分,在(l)的位置(+1),在(r+1)的位置(-1)
转换到具体的点上,就是当点的坐标恰好为(l),在(x)的位置(+1)
恰好为(r+1),在(x)的位置(-1)
修改时减去旧的贡献加上新的贡献即可
代码
#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
inline int read(){
int x=0,fh=1;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e5+5;
int n,m,q,cnt,a[maxn],rt[maxn],latans;
std::vector<int> jll[maxn],jlr[maxn];
struct trr{
int lc,rc,w;
}tr[maxn*40];
int ad(int da,int lat,int l,int r,int wz,int val){
da=++cnt;
tr[da]=tr[lat];
if(l==r){
tr[da].w+=val;
return da;
}
int mids=(l+r)>>1;
if(wz<=mids) tr[da].lc=ad(tr[da].lc,tr[lat].lc,l,mids,wz,val);
else tr[da].rc=ad(tr[da].rc,tr[lat].rc,mids+1,r,wz,val);
tr[da].w=tr[tr[da].lc].w+tr[tr[da].rc].w;
return da;
}
int cx(int da,int l,int r,int x,int y){
if(l>=x && r<=y) {
return tr[da].w;
}
int mids=(l+r)>>1;
if(y<=mids) return cx(tr[da].lc,l,mids,x,y);
else if(x>mids) return cx(tr[da].rc,mids+1,r,x,y);
return cx(tr[da].lc,l,mids,x,y)+cx(tr[da].rc,mids+1,r,x,y);
}
int main(){
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
n=read(),m=read(),q=read();
latans=0;
for(int i=1;i<=n;i++){
a[i]=read();
}
for(int i=1;i<=m;i++){
int l,r,x;
l=read(),r=read(),x=read();
jlr[r+1].push_back(x);
jll[l].push_back(x);
}
for(int i=1;i<=n+1;i++){
rt[i]=rt[i-1];
for(int j=0;j<jlr[i].size();j++){
rt[i]=ad(rt[i],rt[i],1,n,jlr[i][j],-1);
}
for(int j=0;j<jll[i].size();j++){
rt[i]=ad(rt[i],rt[i],1,n,jll[i][j],1);
}
if(i<=n) latans+=cx(rt[i],1,n,1,a[i]);
}
printf("%d
",latans);
for(int i=1;i<=q;i++){
int p,v;
p=read(),v=read();
p^=latans,v^=latans;
latans+=cx(rt[p],1,n,1,v)-cx(rt[p],1,n,1,a[p]);
a[p]=v;
printf("%d
",latans);
}
return 0;
}