BZOJ2333: [SCOI2011]棘手的操作
2016-11-15 21:27
281 查看
Description
有N个节点,标号从1到N,这N个节点一开始相互不连通。第i个节点的初始权值为a[i],接下来有如下一些操作:U x y: 加一条边,连接第x个节点和第y个节点
A1 x v: 将第x个节点的权值增加v
A2 x v: 将第x个节点所在的连通块的所有节点的权值都增加v
A3 v: 将所有节点的权值都增加v
F1 x: 输出第x个节点当前的权值
F2 x: 输出第x个节点所在的连通块中,权值最大的节点的权值
F3: 输出所有节点中,权值最大的节点的权值
Input
输入的第一行是一个整数N,代表节点个数。
接下来一行输入N个整数,a[1], a[2], …, a
,代表N个节点的初始权值。
再下一行输入一个整数Q,代表接下来的操作数。
最后输入Q行,每行的格式如题目描述所示。
Output
对于操作F1, F2, F3,输出对应的结果,每个结果占一行。Sample Input
30 0 0
8
A1 3 -20
A1 2 20
U 1 3
A2 1 10
F1 3
F2 3
A3 -10
F3
Sample Output
-1010
10
HINT
对于30%的数据,保证 N<=100,Q<=10000对于80%的数据,保证 N<=100000,Q<=100000
对于100%的数据,保证 N<=300000,Q<=300000
对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a
<=1000
Source
如果我们能把点重编号 保证在同一个联通块的编号连续 那么可以用线段树直接维护考虑把点重编号 用并查集和链表维护
#include<bits/stdc++.h> using namespace std; const int maxn=300030; int n,m; int nxt[maxn],end[maxn],f[maxn]; int a[maxn],pos[maxn],cnt,b[maxn]; int findfa(int x) { return f[x]==x?x:f[x]=findfa(f[x]); } inline int read() { int tmp=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar(); while(ch>='0'&&ch<='9') tmp=tmp*10+ch-'0',ch=getchar(); return tmp*f; } struct Q { int opt; int x,y; void in() { char ch=getchar(); while(ch<'A'||ch>'Z') ch=getchar(); switch(ch) { case 'U': opt=0; x=read(),y=read(); break; case 'A': opt=read(),x=read(); if(opt<3) y=read(); break; case 'F': opt=read()+3; if(opt<6) x=read(); break; } } }q[maxn]; struct node { int l,r,mx,flag; }e[maxn<<2]; void build(int x,int l,int r) { e[x].l=l,e[x].r=r,e[x].flag=0; if(l==r) { e[x].mx=b[l]; return ; } int mid=l+r>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); e[x].mx=max(e[x<<1].mx,e[x<<1|1].mx); } void pushdown(int x) { e[x<<1].flag+=e[x].flag; e[x<<1].mx+=e[x].flag; e[x<<1|1].flag+=e[x].flag; e[x<<1|1].mx+=e[x].flag; e[x].flag=0; } void modify(int x,int l,int r,int ql,int qr,int v) { if(l==ql&&r==qr) { e[x].mx+=v; e[x].flag+=v; return ; } pushdown(x); int mid=l+r>>1; if(qr<=mid) modify(x<<1,l,mid,ql,qr,v); else if(ql>mid) modify(x<<1|1,mid+1,r,ql,qr,v); else modify(x<<1,l,mid,ql,mid,v),modify(x<<1|1,mid+1,r,mid+1,qr,v); e[x].mx=max(e[x<<1].mx,e[x<<1|1].mx); } int query(int x,int l,int r,int ql,int qr) { // printf("%d %d %d %d\n",l,r,ql,qr); if(l==ql&&r==qr) return e[x].mx; pushdown(x); int mid=l+r>>1; if(qr<=mid) return query(x<<1,l,mid,ql,qr); if(ql>mid) return query(x<<1|1,mid+1,r,ql,qr); return max(query(x<<1,l,mid,ql,mid),query(x<<1|1,mid+1,r,mid+1,qr)); } int main() { // freopen("orz.in","r",stdin); n=read(); for(int i=1;i<=n;i++) a[i]=read(),f[i]=end[i]=i; m=read(); for(int i=1;i<=m;i++) { q[i].in(); if(!q[i].opt) { int fx=findfa(q[i].x),fy=findfa(q[i].y); if(fx!=fy) { f[fy]=fx; nxt[end[fx]]=fy; end[fx]=end[fy]; } } } for(int i=1;i<=n;i++) { if(findfa(i)==i) { for(int j=i;j;j=nxt[j]) pos[j]=++cnt,b[cnt]=a[j]; } } build(1,1,n); for(int i=1;i<=n;i++) f[i]=end[i]=i; for(int i=1;i<=m;i++) { // printf("%d %d\n",i,q[i+1].opt); int fx,fy; switch(q[i].opt) { case 0: fx=findfa(q[i].x),fy=findfa(q[i].y); if(fx!=fy) { f[fy]=fx; end[fx]=end[fy]; } break; case 1: modify(1,1,n,pos[q[i].x],pos[q[i].x],q[i].y); break; case 2: modify(1,1,n,pos[findfa(q[i].x)],pos[end[findfa(q[i].x)]],q[i].y); break; case 3: modify(1,1,n,1,n,q[i].x); break; case 4: printf("%d\n",query(1,1,n,pos[q[i].x],pos[q[i].x])); break; case 5: printf("%d\n",query(1,1,n,pos[findfa(q[i].x)],pos[end[findfa(q[i].x)]])); break; case 6: printf("%d\n",query(1,1,n,1,n)); break; } } return 0; }
相关文章推荐
- 真--可并堆模板--BZOJ2333: [SCOI2011]棘手的操作
- BZOJ2333 [SCOI2011]棘手的操作 【离线 + 线段树】
- bzoj2333 [SCOI2011]棘手的操作
- BZOJ2333: [SCOI2011]棘手的操作
- bZOJ2333 【scoi2011】棘手的操作
- bzoj千题计划218:bzoj2333: [SCOI2011]棘手的操作
- bzoj2333: [SCOI2011]棘手的操作(启发式合并做法)
- bzoj2333 [SCOI2011]棘手的操作
- bzoj2333: [SCOI2011]棘手的操作
- bzoj2333 [SCOI2011]棘手的操作
- BZOJ2333: [SCOI2011]棘手的操作
- bzoj2333 [SCOI2011]棘手的操作
- bzoj2333[SCOI2011]棘手的操作
- bzoj2333[SCOI2011]棘手的操作
- bzoj2333 [SCOI2011]棘手的操作
- bzoj2333: [SCOI2011]棘手的操作 线段树+离线
- bzoj千题计划217:bzoj2333: [SCOI2011]棘手的操作
- [bzoj2333] [SCOI2011]棘手的操作 (可并堆)
- 【SCOI2011】【线段树】棘手的操作
- [可并堆] BZOJ 2333 [SCOI2011]棘手的操作