BZOJ2843:极地旅行社(LCT入门题)
不久之前,Mirko建立了一个旅行社,名叫“极地之梦”。这家旅行社在北极附近购买了N座冰岛,并且提供观光服 务。当地最受欢迎的当然是帝企鹅了,这些小家伙经常成群结队的游走在各个冰岛之间。Mirko的旅行社遭受一次 重大打击,以至于观光游轮已经不划算了。旅行社将在冰岛之间建造大桥,并用观光巴士来运载游客。Mirko希望 开发一个电脑程序来管理这些大桥的建造过程,以免有不可预料的错误发生。这些冰岛从1到N标号。一开始时这些 岛屿没有大桥连接,并且所有岛上的帝企鹅数量都是知道的。每座岛上的企鹅数量虽然会有所改变,但是始终在[0 , 1000]之间。你的程序需要处理以下三种命令: 1."bridge A B"——在A与B之间建立一座大桥(A与B是不同的岛屿)。由于经费限制,这项命令被接受,当且仅当 A与B不联通。若这项命令被接受,你的程序需要输出"yes",之 后会建造这座大桥。否则,你的程序需要输出"no"。 2."penguins A X"——根据可靠消息,岛屿A此时的帝企鹅数量变为X。这项命令只是用来提供信息的,你的程序不 需要回应。 3."excursion A B"——一个旅行团希望从A出发到B。若A与B连通,你的程序需要输出这个旅行团一路上所能看到的 帝企鹅数量(包括起点A与终点B),若不联通,你的程序需要输出"impossible"。 Input 第一行一个正整数N,表示冰岛的数量。 第二行N个范围[0, 1000]的整数,为每座岛屿初始的帝企鹅数量。 第三行一个正整数M,表示命令的数量。接下来M行即命令,为题目描述所示。 1<=N<=30000,1<=M<=100000 Output 对于每个bridge命令与excursion命令,输出一行,为题目描述所示。 Sample Input 5 4 2 4 5 6 10 excursion 1 1 excursion 1 2 bridge 1 2 excursion 1 2 bridge 3 4 bridge 3 5 excursion 4 5 bridge 1 3 excursion 2 4 excursion 2 5 Sample Output 4 impossible yes 6 yes yes 15 yes 15 16
题意:给定N个岛屿,每个岛屿有初始数量的企鹅。现在有如下三种操作:
1. "bridge A B"——----在A与B之间建立一座大桥(A与B是不同的岛屿)。如果A、B连通,输出"yes",且建造这座大桥。否则,输出"no"。
2. "penguins A X"——岛屿A此时的帝企鹅数量变为X。
3. "excursion A B"——若A与B连通,输出路线上帝企鹅数量(包括起点A与终点B);否则,输出"impossible"。
思路:好像没什么可以说的,毕竟同样是基础题,而前面已经详细地解释过了。
唯一需要注意的是:
access的时候也需要update:
因为这里和单纯的平衡树题统链上信息不同,这里access函数会使原树变化(即splay树也相应变化),所以update的值相应变化。
#include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; const int maxn=500010; int val[maxn]; struct LCT { int sum[maxn],rev[maxn],ch[maxn][2],fa[maxn],stc[maxn],top; int isroot(int x){ return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; } int get(int x){ return ch[fa[x]][1]==x; } void pushdown(int x) { if(!rev[x]||!x) return ; swap(ch[x][0],ch[x][1]); if(ch[x][0]) rev[ch[x][0]]^=1; if(ch[x][1]) rev[ch[x][1]]^=1; rev[x]=0; } void pushup(int x) { sum[x]=val[x]; if(ch[x][0]) sum[x]+=sum[ch[x][0]]; if(ch[x][1]) sum[x]+=sum[ch[x][1]]; } void rotate(int x) { int old=fa[x],fold=fa[old],opt=get(x); if(!isroot(old)) ch[fold][get(old)]=x; fa[x]=fold; ch[old][opt]=ch[x][opt^1]; fa[ch[old][opt]]=old; ch[x][opt^1]=old; fa[old]=x; pushup(old); pushup(x); } void splay(int x) { int top=0; stc[++top]=x; for(int i=x;!isroot(i);i=fa[i]) stc[++top]=fa[i]; for(int i=top;i;i--) pushdown(stc[i]); for(int f;!isroot(x);rotate(x)){ if(!isroot(f=fa[x])) rotate(get(x)==get(f)?f:x); } } void access(int x) { int rson=0; for(;x;rson=x,x=fa[x]){ splay(x); ch[x][1]=rson; pushup(x); } } int find(int x){ access(x); splay(x); while(ch[x][0]) x=ch[x][0]; return x;} void change(int a,int x){ val[a]=x; access(a); splay(a); } int query(int x,int y) { make_root(y); access(x); splay(x); return sum[x]; } void make_root(int x) { access(x); splay(x); rev[x]^=1; } void link(int x,int y) { make_root(x); fa[x]=y; splay(x); } }S; int main() { int N,M,a,b; char opt[20]; scanf("%d",&N); for(int i=1;i<=N;i++) scanf("%d",&val[i]); scanf("%d",&M); while(M--){ scanf("%s%d%d",opt,&a,&b); if(opt[0]=='b'){ if(S.find(a)!=S.find(b)){ printf("yes\n"); S.link(a,b); } else printf("no\n"); } if(opt[0]=='p') S.change(a,b); if(opt[0]=='e'){ if(S.find(a)!=S.find(b)) printf("impossible\n"); else printf("%d\n",S.query(a,b)); } } return 0; }
It is your time to fight!