传送门-P2843
(1180是权限题,所以就不放了)
写在前面:为什么BZOJ上LCT好多都是权限题(╯‵□′)╯︵┻━┻
思路:判断联通用findroot函数(洞穴探测里已经说过了);修改x的操作可以把x旋转到所在的splay的根上来,再修改;查询的话把x,y分别access到同一棵splay上,splay操作后求值即可
注意:无
代码:
#include<bits/stdc++.h>
#define pd(i) (i>='0'&&i<='9')
using namespace std;
int n,m,x,y;
int stacks[30010];
char s[10];
struct tree
{
int fa,ch[2],sum,data;
bool lazy;
}a[200010];
int in()
{
int t=0;
char ch=getchar();
while (!pd(ch)) ch=getchar();
while (pd(ch)) t=(t<<3)+(t<<1)+ch-'0',ch=getchar();
return t;
}
void ct(int x)
{
a[x].sum=a[a[x].ch[0]].sum+a[a[x].ch[1]].sum+a[x].data;
}
#define isroot(x) (a[a[x].fa].ch[0]!=x&&a[a[x].fa].ch[1]!=x)
void pushdown(int x)
{
if (!a[x].lazy) return;
a[a[x].ch[0]].lazy^=1;
a[a[x].ch[1]].lazy^=1;
swap(a[x].ch[0],a[x].ch[1]);
a[x].lazy=0;
}
void rorate(int x,bool mk)
{
int y=a[x].fa;
a[x].fa=a[y].fa;
if (!isroot(y))
{
if (a[a[y].fa].ch[0]==y) a[a[y].fa].ch[0]=x;
else a[a[y].fa].ch[1]=x;
}
a[y].ch[!mk]=a[x].ch[mk];
a[a[x].ch[mk]].fa=y;
a[x].ch[mk]=y;
a[y].fa=x;
ct(y);ct(x);
}
void splay(int x)
{
int y,cnt=0,k=x;
stacks[++cnt]=k;
while (!isroot(k)) k=a[k].fa,stacks[++cnt]=k;
for (int i=cnt;i;i--) pushdown(stacks[i]);
while (!isroot(x))
{
y=a[x].fa;
if (isroot(y))
{
if (a[y].ch[0]==x) rorate(x,1);
else rorate(x,0);
}
else if (a[a[y].fa].ch[0]==y)
{
if (a[y].ch[0]==x) rorate(y,1);
else rorate(x,0);
rorate(x,1);
}
else
{
if (a[y].ch[1]==x) rorate(y,0);
else rorate(x,1);
rorate(x,0);
}
}
}
void access(int x)
{
for (int y=0;x;y=x,x=a[x].fa)
splay(x),
a[x].ch[1]=y,
ct(x);
}
void link(int x,int y)
{
access(x);
splay(x);
a[x].lazy^=1;
a[x].fa=y;
}
void cut(int x,int y)
{
access(x);
splay(x);
a[x].lazy^=1;
access(y);
splay(y);
a[x].fa=a[y].ch[0]=0;
ct(y);
}
int findroot(int x)
{
access(x);
splay(x);
while (a[x].ch[0]) x=a[x].ch[0];
return x;
}
main()
{
n=in();
for (int i=1;i<=n;i++)
a[i].data=in(),
a[i].sum=a[i].data;
scanf("%d",&m);
while (m--)
{
scanf("%s",s);
x=in();y=in();
if (s[0]=='b')
{
if (findroot(x)==findroot(y)) puts("no");
else puts("yes"),link(x,y);
}
else if (s[0]=='p')
{
splay(x);
a[x].sum+=(y-a[x].data);
a[x].data=y;
}
else
{
if (findroot(x)!=findroot(y)) puts("impossible");
else
access(x),
splay(x),
a[x].lazy^=1,
access(y),
splay(y),
printf("%d\n",a[y].sum);
}
}
}
本文介绍了一道BZOJ上的LCT权限题目,详细解析了使用splay树解决该问题的方法,包括findroot函数用于判断联通性,access操作用于路径压缩,link和cut操作用于维护树结构,以及如何通过splay操作来更新节点信息。

247

被折叠的 条评论
为什么被折叠?



