bzoj1180 [CROATIAN2009]OTOCI(详解LCT操作)
来源:互联网 发布:大连爱知时计科技 编辑:程序博客网 时间:2024/05/18 21:39
Description
给出n个结点以及每个点初始时对应的权值wi。起始时点与点之间没有连边。有3类操作: 1、bridge A B:询问结点A与结点B是否连通。如果是则输出“no”。否则输出“yes”,并且在结点A和结点B之间连一条无向边。 2、penguins A X:将结点A对应的权值wA修改为X。 3、excursion A B:如果结点A和结点B不连通,则输出“impossible”。否则输出结点A到结点B的路径上的点对应的权值的和。给出q个操作,要求在线处理所有操作。数据范围:1<=n<=30000, 1<=q<=300000, 0<=wi<=1000。
Input
第一行包含一个整数n(1<=n<=30000),表示节点的数目。第二行包含n个整数,第i个整数表示第i个节点初始时对应的权值。第三行包含一个整数q(1<=n<=300000),表示操作的数目。以下q行,每行包含一个操作,操作的类别见题目描述。任意时刻每个节点对应的权值都是1到1000的整数。
Output
输出所有bridge操作和excursion操作对应的输出,每个一行。
Sample Input
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
impossible
yes
6
yes
yes
15
yes
15
16
分析:发现一个讲得很好的[blog](http://blog.csdn.net/JeremyGJY/article/details/51078087)这篇blog使我对LCT的各个操作有了更清晰的理解我们只要记住:
expose是访问操作,可以把x与根节点的路径变成偏爱路径
makeroot是换根操作,可以把树形结构的根换成x
其余的所有操作都是建立在这两个操作上的
Cut:
我们需要断开(x,y)
同理,我们先把x变成整棵树的根节点
之后我们expose(y),splay(y),
因为(x,y)之前是相连的,所以这样操作之后,x和y一定在一个辅助树中
x是根节点,ta的深度最小,y是辅助树的根节点
所以x一定是y的左儿子
pre[x]=0,ch[y][0]=0
Link:
我们要连接(x,y)
既然我们能够cut,那我们就可以link
于是我们可以先把整棵树的根节点变成x:(makeroot(x)),这样x就没有pre了
所以我们只要简单的把pre[x]变成y即可
Find:
这个操作可以把找到当前树结构中的根节点
我们只要访问一下x,把ta转换到辅助树的根上
之后一路向左找就可以了(根节点一定是深度最浅的一个点)
两点连通性:
find(x)==find(y)
显而易见
路径权值和:
LCT的优点就是ta的形态不固定
我们可以把路径中的一个端点视为根节点(比如说x):makeroot(x)
之后只要expose(y),这样x到y的路径就变成了偏爱路径,
splay(y),y节点上的sum就是路径权值和啦
节点到根的距离:
首先我们要把给定的根换到根的位置上:makeroot(root)
之后就像询问路径权值和一样
expose(x),splay(x),
返回值是size[ch[x][0]]
更改节点值:
我们要改变一个结点的权值,
我们当然希望涉及到的结点尽量少,那么什么样的结点改变ta的值影响的结点维护值最少呢,当然是根节点
所以我们首先makeroot(x)
直接修改x的值就可以了
最后不要忘了update(x)
tip
rotate,splay,expose,makeroot这四个过程是最重要的
一定不要写错了
#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int N=300010;int pre[N],ch[N][2],v[N],sum[N],q[N];bool rev[N];int n,m;int get(int bh){ return (ch[pre[bh]][0]==bh ? 0:1);}int isroot(int bh){ return ch[pre[bh]][0]!=bh&&ch[pre[bh]][1]!=bh;}void update(int bh){ if (!bh) return; sum[bh]=v[bh]; if (ch[bh][0]) sum[bh]+=sum[ch[bh][0]]; if (ch[bh][1]) sum[bh]+=sum[ch[bh][1]];}void push(int bh){ int lc=ch[bh][0]; int rc=ch[bh][1]; if (bh&&rev[bh]) { if (lc) rev[lc]^=1; if (rc) rev[rc]^=1; rev[bh]^=1; swap(ch[bh][0],ch[bh][1]); }}void rotate(int bh){ int fa=pre[bh]; int grand=pre[fa]; int wh=get(bh); if (!isroot(fa)) ch[grand][ch[grand][0]==fa ? 0:1]=bh; pre[bh]=grand; ch[fa][wh]=ch[bh][wh^1]; pre[ch[fa][wh]]=fa; ch[bh][wh^1]=fa; pre[fa]=bh; update(fa); update(bh);}void splay(int bh){ int top=0; q[++top]=bh; for (int i=bh;!isroot(i);i=pre[i]) //!isroot(i) q[++top]=pre[i]; while (top) push(q[top--]); for (int fa;!isroot(bh);rotate(bh)) if (!isroot(fa=pre[bh])) rotate(get(fa)==get(bh)? fa:bh);}void expose(int bh){ int t=0; while (bh) { splay(bh); ch[bh][1]=t; update(bh); //产生了一个新儿子,所以需要update t=bh; bh=pre[bh]; }}void makeroot(int bh) //把bh变成树的根 { expose(bh); splay(bh); rev[bh]^=1;}void link(int x,int y){ makeroot(x); //这样x就没有pre了 pre[x]=y; }void cut(int x,int y){ makeroot(x); expose(y); splay(y); //这样x一定在y的左儿子中 pre[x]=ch[y][0]=0; update(x);}int find(int bh){ expose(bh); //访问一下,使得根到bh的路径变成偏爱路径 splay(bh); while (ch[bh][0]) bh=ch[bh][0]; return bh;}int main(){ char s[30]; scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&v[i]),sum[i]=v[i]; scanf("%d",&m); for (int i=1;i<=m;i++) { scanf("%s",s); int x,y; scanf("%d%d",&x,&y); if (s[0]=='e') //路径权值和 { if (find(x)!=find(y)) printf("impossible\n"); else { makeroot(x); expose(y); splay(y); printf("%d\n",sum[y]); } } else if (s[0]=='b') { if (find(x)!=find(y)) printf("yes\n"),link(x,y); else printf("no\n"); } else { makeroot(x); //改变单个结点值 splay(x); v[x]=y; update(x); } } return 0;}
- bzoj1180 [CROATIAN2009]OTOCI(详解LCT操作)
- [BZOJ1180][CROATIAN2009]OTOCI(LCT)
- 【bzoj1180】【CROATIAN2009】【OTOCI】【lct】
- [BZOJ1180][CROATIAN2009][LCT]OTOCI
- bzoj1180: [CROATIAN2009]OTOCI(lct)
- BZOJ1180 [CROATIAN2009]OTOCI
- bzoj1180: [CROATIAN2009]OTOCI
- [BZOJ1180] [CROATIAN2009]OTOCI
- [BZOJ1180][CROATIAN2009]OTOCI
- 【bzoj1180】[CROATIAN2009]OTOCI
- bzoj1180: [CROATIAN2009]OTOCI
- BZOJ1180: [CROATIAN2009]OTOCI
- 【bzoj1180】[CROATIAN2009]OTOCI
- 【bzoj1180】OTOCI LCT
- BZOJ 1180: [CROATIAN2009]OTOCI (LCT题解)
- BZOJ1180 OTOCI(LCT动态树)
- [bzoj1180][CROATIAN2009]OTOCI Link-Cut-Tree
- bzoj 1180 [CROATIAN2009]OTOCI - LCT
- 调试神经网络的注意事项和技巧总结(一)
- 面向对象(三)
- 【Android】手机屏幕分辨率与dip、dp、sp的区别
- 纪念博客开通
- 51单片机
- bzoj1180 [CROATIAN2009]OTOCI(详解LCT操作)
- TCP 协议详解
- iOS多线程概要
- Ubuntu下安装Atom
- java应用——高仿XP画板(二:实现部分监听)
- KEIL C51 printf格式化输出特殊用法
- [爱奇艺]校招笔试(2017/9/11)
- HDOJ 2106 decimal system(进制)
- criteria获取属性值