题解部落冲突
Posted h-lka
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解部落冲突相关的知识,希望对你有一定的参考价值。
LCT学习ing……从FlshHu的大佬的博客中看到此题,于是便写了一下。
题目背景
在一个叫做Travian的世界里,生活着各个大大小小的部落。其中最为强大的是罗马、高卢和日耳曼。他们之间为了争夺资源和土地,进行了无数次的战斗。期间诞生了众多家喻户晓的英雄人物,也留下了许多可歌可泣的动人故事。
其中,在大大小小的部落之间,会有一些道路相连,这些道路是Travian世界里的重要枢纽,简单起见,你可以把这些部落与部落之间相连的道路看作一颗树,可见每条道路对于Travian世界的重要程度。有了这些道路,建筑工人就可以通过这些道路进行友好外交啦。
然而,事情并不会像想象的那样美好,由于资源的匮乏,相邻的部落(由一条道路相连的部落)之间经常会发生大大小小的冲突事件,更有甚者,会升级为部落之间的大型战争。
为了避免误伤,每当两个相邻的部落之间发生大型战争之时,这两个部落间的道路是不允许通行的,对于一些强大的部落,甚至能与多个相邻的部落同时开战,同样的,这些战争地带的道路十分危险,是不可通行的。
天下之势,分久必合,当两个部落经历了不打不相识的苦战之后,他们可以签订停战协议(暂时停战,以后依旧可能再次开战),这样,两个部落之间的道路又会重新恢复为可通行状态,建筑工人们又可以经过此地购买最新的大本营设计图纸来强大自己的部落了。
为了简单起见,我们把各大战争事件按发起的时间顺序依次编号(最先发起的战争编号就为 1,第二次战争编号就为 2,以此类推),当两个部落停战之时,则会直接告诉你这场战争的编号,然后这场战争就载入了史册,不复存在了,当然,这并不会影响到其他战争的编号。
建筑工人十分讨厌战争,因为战争,想从一个部落到另一个部落进行友好交流的建筑工人可能就此白跑一趟。所以,在他们出发之前,都会向你问问能不能到达他们想去的部落。
题目描述
简单起见,你就是要处理下面三件事,所有的事件都是按照时间顺序给出的。
1.(Q p q)从第 p 个部落出发的建筑工人想知道能否到达第 q 个部落了,你要回答的便是(Yes/No),注意大小写
2.(C p q)第 p 个部落与第 q 个部落开战了,保证他们一定是相邻的部落,且目前处于停战(未开战)状态
3.(U x ) 第 x 次发生的战争结束了,它将永远的被载入史册,不复存在(保证这个消息不会告诉你多次)
输入输出格式
输入格式:
第一行两个数 n 和 m, n 代表了一共有 n 个部落,m 代表了以上三种事件发生的总数
接下来的 n - 1行,每行两个数 p , q,代表了第 p 个部落与第 q 个部落之间有一条道路相连
接下来的 m 行,每行表示一件事,详见题目描述
输出格式:
每行一个“Yes”或者“No”,表示从第 p 个部落出发的建筑工人能否到达第 q 个部落
输入样例:
5 9 1 2 2 3 3 4 4 5 Q 1 4 C 2 1 C 4 3 Q 3 1 Q 1 5 U 1 U 2 C 4 3 Q 3 4
输出样例:
Yes
No
No
No
解:
题目中要求三个操作,对于Q操作,我们用LCT动态维护连通性,每次判断即可。
对于C操作,Cut即可。
对于U操作,Link即可。
我们开一个u,v数组,直接linkcut不方便,用数组存每次连和切的边即可。
具体实现见代码。
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; int n,m,a,b,u[500000],v[500000],p; char c[20]; struct node int fa,ch[2],rev; tr[500000]; inline bool root(int x) int g=tr[x].fa; return !(tr[g].ch[1]==x||tr[g].ch[0]==x); inline void pushr(int x) if(!x)return; swap(tr[x].ch[0],tr[x].ch[1]); tr[x].rev^=1; inline void pushdown(int x) if(tr[x].rev) pushr(tr[x].ch[0]); pushr(tr[x].ch[1]); tr[x].rev=0; inline void push(int x) if(!root(x))push(tr[x].fa); pushdown(x); inline void rotate(int x) int y=tr[x].fa,z=tr[y].fa,k=tr[y].ch[1]==x; if(!root(y))tr[z].ch[tr[z].ch[1]==y]=x; tr[x].fa=z;tr[y].ch[k]=tr[x].ch[k^1]; if(tr[x].ch[k^1])tr[tr[x].ch[k^1]].fa=y; tr[x].ch[k^1]=y;tr[y].fa=x;//pushup(y);pushup(x); inline void splay(int x) int y,z; push(x); while(!root(x)) y=tr[x].fa,z=tr[y].fa; if(!root(y))(tr[z].ch[1]==y)^(tr[y].ch[1]==x)?rotate(x):rotate(y); rotate(x); //pushup(x); inline void access(int x) for(int y=0;x;y=x,x=tr[x].fa) splay(x);tr[x].ch[1]=y;//pushup(x); inline void makeroot(int x) access(x);splay(x);pushr(x); inline void split(int x,int y) makeroot(x);access(y);splay(y); inline void link(int x,int y) makeroot(x);tr[x].fa=y; inline void cut(int x,int y) split(x,y);tr[x].fa=tr[y].ch[0]=0; inline int findroot(int x) access(x);splay(x); while(tr[x].ch[0])x=tr[x].ch[0]; return x; int main() scanf("%d%d",&n,&m); for(int i=1;i<n;++i) scanf("%d%d",&a,&b); link(a,b); for(register int i=1;i<=m;i++) cin>>c; if(c[0]==‘Q‘) scanf("%d%d",&a,&b); findroot(a)==findroot(b)?printf("Yes\n"):printf("No\n"); else if(c[0]==‘C‘) scanf("%d%d",&a,&b); ++p; cut(u[p]=a,v[p]=b); else scanf("%d",&a); link(u[a],v[a]); return 0;
以上是关于题解部落冲突的主要内容,如果未能解决你的问题,请参考以下文章