Codeforces 1638 E. Colorful Operations —— 线段树+暴力,有丶东西
作者:互联网
题意:
给你一个长度为n的数组a,一开始所有位置的颜色都为1,值都为0.每次有三种操作:
Color l r x:把[l,r]中的所有位置颜色变成x
Add c:把颜色为c的所有位置的值加上c
Query i:问i位置的值是多少。
题解:
这个感觉还是有点绕的,我也是想了比较长的一段时间。最后在通过某位大佬的代码证实了我的想法之后才敲的,要不然我敲崩了又没有借鉴可以参考,非常难受。
首先这种区间变换的题目,很容易就能想到是区间修改,但是有的时候也不一定,所以我在决定做法的时候还是犹豫了一段时间的。
使用multiset维护每一段颜色。这样子的话Color l r x 的时候只需要把在l,r内部的删掉,然后两端的修改一下即可,这个时间复杂度应当是
O
(
N
l
o
g
N
)
O(NlogN)
O(NlogN),因为你删掉的区间必然需要一次操作建立起来,所以复杂度可证不会很大。
然后呢?对于加值的问题,我们如果每次都把所有的对应颜色区间操作的话,时间复杂度就会很高了。所以此时应该是延时操作。
那么如何操作?
sum[i]表示从开始操作到现在,颜色为i的值之和是多少。
但是肯定出现一个情况就是说,后来新加入的颜色怎么办?
然后注意到我们新加入的颜色是一个区间的形式,那么我只要在这一段区间加入这个颜色的时候,区间修改这一段区间在线段树中的值是-sum[i]不就好了吗,然后sum和线段树对应的值一加,就相互抵消了。
然后颜色i变成颜色j的时候该怎么办,那么我们只需要在区间中加上sum[i]就可以了。和上面的操作连接起来,就变成了:
颜色i变成j的时候,首先加上sum[i]表示拿到之前的所有Add i操作,然后在减去sum[j]表示消去Add j操作的影响。这样子最终的值就是sum[j]+线段树单点查询的值。
最好还是看代码,一些变量解释:
st 表示存当前所有的颜色区间
col[i]表示以i开头的区间颜色
sum[i]表示从开头到现在,颜色i的值之和
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+5;
ll s[N*4],f[N*4];
void push_down(int root){
if(!f[root])return ;
s[root<<1]+=f[root];
s[root<<1|1]+=f[root];
f[root<<1]+=f[root];
f[root<<1|1]+=f[root];
f[root]=0;
}
void update(int l,int r,int root,int ql,int qr,ll v){
if(l>=ql&&r<=qr){
s[root]+=v;
f[root]+=v;
return ;
}
push_down(root);
int mid=l+r>>1;
if(mid>=ql)update(l,mid,root<<1,ql,qr,v);
if(mid<qr)update(mid+1,r,root<<1|1,ql,qr,v);
s[root]=s[root<<1]+s[root<<1|1];
}
ll query(int l,int r,int root,int p){
if(l==r)return s[root];
push_down(root);
int mid=l+r>>1;
if(mid>=p)return query(l,mid,root<<1,p);
return query(mid+1,r,root<<1|1,p);
}
#define pii pair<int,int>
const int mx=1e9+7;
multiset<pii>st;
ll sum[N];
int col[N];
int main()
{
char s[15];
int n,m,l,r,v;
scanf("%d%d",&n,&m);
st.insert({0,0}),st.insert({mx,mx}),st.insert({1,n});
col[1]=1;
while(m--){
scanf("%s",s);
if(s[0]=='C'){
scanf("%d%d%d",&l,&r,&v);
multiset<pii>::iterator it=st.upper_bound({l,mx});it--;
while(it->first<=r){
auto [x,y]=*it;
st.erase(it++);
if(x<l)st.insert({x,l-1});
if(y>r)st.insert({r+1,y}),col[r+1]=col[x];
update(1,n,1,max(l,x),min(r,y),sum[col[x]]);
}
st.insert({l,r});
col[l]=v;
update(1,n,1,l,r,-sum[v]);
}
else if(s[0]=='A')
scanf("%d%d",&l,&v),sum[l]+=v;
else{
scanf("%d",&l);
multiset<pii>::iterator it=st.upper_bound({l,mx});
it--;
printf("%lld\n",query(1,n,1,l)+sum[col[it->first]]);
}
}
return 0;
}
标签:Operations,颜色,Colorful,1638,sum,st,int,root,col 来源: https://blog.csdn.net/tianyizhicheng/article/details/123224320