【题解】「SCOI2011」棘手的操作

挺妙的一道题。

我们用线段树来解决这个问题。

考虑集合内加 v 这个操作。

如果我们把它转化为区间操作就好了。

那么我们要求编号连续。

怎么给每个点编号呢?首先把操作序列离线下来,然后用带权并查集维护在集合内的 相对编号 ,合并的时候把被合并的集合的 相对编号 都加上合并集合的大小即可。

时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

#include<bits/stdc++.h> #define lc(x) t[x].ch[0] #define rc(x) t[x].ch[1] #define ll long long using namespace std; const int N=3e5+5; int n,Q,fa[N],val[N],siz[N],id[N],L[N],R[N]; ll a[N],sum; char ch[100]; struct query{ int type,x,y; }q[N]; struct node{ ll dat,max; }t[N<<2]; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } //带秩并查集维护编号 //cjg yyds ! int find(int x) { if(fa[x]==x) return x; int y=fa[x]; fa[x]=find(fa[x]); val[x]+=val[y]; return fa[x]; } void unionset(int x,int y) { int u=find(x),v=find(y); if(u!=v) { fa[u]=v; val[u]+=siz[v]; siz[v]+=siz[u]; } } int find2(int x) { return fa[x]==x?x:fa[x]=find2(fa[x]); } void unionset2(int x,int y) { int u=find2(x),v=find2(y); if(u!=v) { fa[u]=v; L[v]=min(L[v],L[u]); R[v]=max(R[v],R[u]); } } void pushup(int p) { t[p].max=max(t[p<<1].max,t[p<<1|1].max); } void pushdown(int p) { if(t[p].dat) { t[p<<1].dat+=t[p].dat; t[p<<1].max+=t[p].dat; t[p<<1|1].dat+=t[p].dat; t[p<<1|1].max+=t[p].dat; t[p].dat=0; } } void upd(int p,int l,int r,int ql,int qr,ll x) { if(ql<=l&&r<=qr) { t[p].max+=x; t[p].dat+=x; return; } pushdown(p); int mid=(l+r)/2; if(ql<=mid) upd(p<<1,l,mid,ql,qr,x); if(mid<qr) upd(p<<1|1,mid+1,r,ql,qr,x); pushup(p); } ll qry(int p,int l,int r,int ql,int qr) { if(ql<=l&&r<=qr) { return t[p].max; } pushdown(p); int mid=(l+r)/2; if(qr<=mid) return qry(p<<1,l,mid,ql,qr); else if(mid<ql) return qry(p<<1|1,mid+1,r,ql,qr); else return max(qry(p<<1,l,mid,ql,qr),qry(p<<1|1,mid+1,r,ql,qr)); } int main() { srand(time(0)); n=read(); for(int i=1;i<=n;i++) { a[i]=read(); siz[i]=1; fa[i]=i; } Q=read(); for(int i=1;i<=Q;i++) { scanf("%s",ch); if(ch[0]=='U') { q[i].type=0; q[i].x=read(),q[i].y=read(); unionset(q[i].x,q[i].y); } else if(ch[0]=='A'&&ch[1]=='1') { q[i].type=1; q[i].x=read(),q[i].y=read(); } else if(ch[0]=='A'&&ch[1]=='2') { q[i].type=2; q[i].x=read(),q[i].y=read(); } else if(ch[0]=='A'&&ch[1]=='3') { q[i].type=3; q[i].x=read(); } else if(ch[0]=='F'&&ch[1]=='1') { q[i].type=4; q[i].x=read(); } else if(ch[0]=='F'&&ch[1]=='2') { q[i].type=5; q[i].x=read(); } else { q[i].type=6; } } for(int i=2;i<=n;i++) { unionset(i,1); } for(int i=1;i<=n;i++) { find(i); id[i]=val[i]+1; } for(int i=1;i<=n;i++) { fa[i]=i; L[i]=R[i]=id[i]; } for(int i=1;i<=n;i++) { upd(1,1,n,id[i],id[i],a[i]); } for(int i=1;i<=Q;i++) { if(q[i].type==0) { unionset2(q[i].x,q[i].y); } else if(q[i].type==1) { upd(1,1,n,id[q[i].x],id[q[i].x],q[i].y); } else if(q[i].type==2) { int x=find2(q[i].x); upd(1,1,n,L[x],R[x],q[i].y); } else if(q[i].type==3) { upd(1,1,n,1,n,q[i].x); } else if(q[i].type==4) { printf("%lld\n",qry(1,1,n,id[q[i].x],id[q[i].x])); } else if(q[i].type==5) { int x=find2(q[i].x); printf("%lld\n",qry(1,1,n,L[x],R[x])); } else { printf("%lld\n",t[1].max); } } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530177.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(5)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示