P5524 [Ynoi2012] NOIP2015 充满了希望 做题记录
P5524 [Ynoi2012] NOIP2015 充满了希望
Description
给一个长为 \(n\) 的序列,有 \(m\) 个操作,操作编号从 \(1\) 到 \(m\),每个操作为:
1 x y:将序列位置为 \(x,y\) 的两个元素交换。
2 l r x:将序列区间 \([l,r]\) 内所有元素修改为 \(x\)。
3 x:查询序列 \(x\) 位置的值。
现在有 \(q\) 次查询,每次查询给出一个操作的区间 \([l,r]\):
先将序列中的元素全部置为 \(0\),之后依次进行从 \(l\) 到 \(r\) 的所有操作,求出所有这些操作中所有 \(3\) 操作的答案的和。
查询之间独立。
\(1\le n,m,q\le 10^6\),\(1\le x\le 10^9\)。
Solution
Subtask 3:没有 2 操作
操作中只有交换和查询,可以发现在任意时刻的任意位置都没有值,直接输出 \(0\)。
Subtask 4:没有 1 操作
操作中只有区间赋值和查询。
可以发现,在某一个时刻 \(a_x\) 的值,只受到上一次覆盖到它的区间赋值操作的影响。
我们在每一个时刻,对每一个位置都维护出一个 \(t_x\),表示这个位置上一次覆盖到它的操作的编号。
如果一个编号为 \(i\) 的 \(3\) 操作要对一个询问 \(l,r\) 造成贡献,那么需要满足 \(l\in[1,t_x],r\in[i,m]\)。
转化为二维偏序问题,将 \(l\) 作为 \(x\) 轴,将 \(r\) 作为 \(y\) 轴,扫描线+树状数组维护答案,线段树维护 \(t_x\)。
Overall
仍然用线段树维护 \(t_x\)。对于 2 操作,对应着区间推平;对于 1 操作,对应单点修改。
剩下的和 Subtask 4 一样的做法。
int n,m,Q,k;
int val[N];
struct Segtr{
int val,cov;
bool tag;
}tr[N<<2];
struct SegTree{
void Spread(int p){
if(!tr[p].tag) return;
tr[p<<1].val=tr[p<<1|1].val=tr[p].cov;
tr[p<<1].cov=tr[p<<1|1].cov=tr[p].cov;
tr[p<<1].tag=tr[p<<1|1].tag=1;
tr[p].cov=0,tr[p].tag=0;
}
void Cover(int p,int l,int r,int L,int R,int v){
if(L<=l&&r<=R){
tr[p].val=v;
tr[p].tag=1,tr[p].cov=v;
return;
}
int mid=(l+r)>>1; Spread(p);
if(L<=mid) Cover(p<<1,l,mid,L,R,v);
if(R>mid) Cover(p<<1|1,mid+1,r,L,R,v);
}
void Update(int p,int l,int r,int x,int v){
if(l==r){
tr[p].val=v;
return;
}
int mid=(l+r)>>1; Spread(p);
if(x<=mid) Update(p<<1,l,mid,x,v);
else Update(p<<1|1,mid+1,r,x,v);
}
int Ask(int p,int l,int r,int x){
if(l==r) return tr[p].val;
int mid=(l+r)>>1; Spread(p);
if(x<=mid) return Ask(p<<1,l,mid,x);
else return Ask(p<<1|1,mid+1,r,x);
}
}Seg;
struct Point{
int x,y,v,id;
bool operator<(const Point& tmp)const{
if(x!=tmp.x) return x<tmp.x;
else if(y!=tmp.y) return y<tmp.y;
else return id<tmp.id;
}
}c[N<<2];
struct Fenwick{
ll tr[N];
void Update(int x,int v){
for(;x<=m;x+=x&-x) tr[x]+=v;
}
ll Ask(int x){
ll res=0;
for(;x;x-=x&-x) res+=tr[x];
return res;
}
}Bit;
ll ans[N];
signed main(){
read(n),read(m),read(Q);
for(int i=1;i<=m;i++){
int op,l,r;
read(op);
if(op==1){
read(l),read(r);
int px=Seg.Ask(1,1,n,l);
int py=Seg.Ask(1,1,n,r);
Seg.Update(1,1,n,l,py);
Seg.Update(1,1,n,r,px);
}
else if(op==2){
read(l),read(r),read(val[i]);
Seg.Cover(1,1,n,l,r,i);
}
else{
int x; read(x);
int p=Seg.Ask(1,1,n,x);
if(!val[p]) continue;
c[++k]={1,i,val[p],0};
c[++k]={p+1,i,-val[p],0};
}
}
for(int i=1;i<=Q;i++){
int l,r; read(l),read(r);
c[++k]={l,r,0,i};
}
sort(c+1,c+k+1);
for(int i=1;i<=k;i++){
if(c[i].id==0)
Bit.Update(c[i].y,c[i].v);
else ans[c[i].id]=Bit.Ask(c[i].y);
}
for(int i=1;i<=Q;i++) printf("%lld\n",ans[i]);
return 0;
}

浙公网安备 33010602011771号