您的位置:首页 > 其它

BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊 ——Link-Cut Tree

2016-12-18 17:41 507 查看

【题目分析】

    以前用分块的方法做过这道题目,现在再用LCT水一边,发现思路确实巧妙。

    每次弹射,可以看作在一条边上走了过去,而且很重要的性质,每一个点的出边只有一条。

    那么就很容易知道,可以用LCT维护连通性,然后把n+1这个虚点当作根,把起点旋转上去,然后n+1的深度就是结果的值。

    更进一步,由于偏爱路径只是起点到n+1,深度又改为了子树大小size的查询。

    均摊复杂度NlogN

【代码】

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>

#include <set>
#include <map>
#include <string>
#include <algorithm>
#include <vector>
#include <iostream>
#include <queue>

using namespace std;

#define maxn 1000005
#define inf (0x3f3f3f3f)

int read()
{
int x=0,f=1; char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}

int fa[maxn],ch[maxn][2],siz[maxn],rev[maxn],top=0,sta[maxn];

bool isroot(int x)
{
return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}

void update(int x)
{
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}

void pushdown(int x)
{
if (rev[x])
{
rev[x]^=1;
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
}
}

void rot(int x)
{
int y=fa[x],z=fa[y],l,r;
if (ch[y][0]==x) l=0; else l=1;
r=l^1;
if (!isroot(y))
{
if (ch[z][0]==y) ch[z][0]=x;
else ch[z][1]=x;
}
fa[x]=z; fa[y]=x; fa[ch[x][r]]=y;
ch[y][l]=ch[x][r]; ch[x][r]=y;
update(y); update(x);
}

void splay(int x)
{
int top=0; sta[++top]=x;
for (int i=x;!isroot(i);i=fa[i]) sta[++top]=fa[i];
while (top) pushdown(sta[top--]);
while (!isroot(x))
{
int y=fa[x],z=fa[y];
if (!isroot(y))
{
if (ch[y][0]==x^ch[z][0]==y) rot(x);
else rot(y);
}
rot(x);
}
}

void access(int x)
{
for (int t=0;x;t=x,x=fa[x])
{
splay(x);
ch[x][1]=t;
update(x);
}
}

void makeroot(int x)
{
access(x);
splay(x);
rev[x]^=1;
}

int find(int x)
{
access(x);
splay(x);
while (ch[x][0]) x=ch[x][0];
return x;
}

void link(int x,int y)
{
//  printf("link %d %d\n",x,y);
makeroot(x);
fa[x]=y;
//  update(x);update(y);
}

void cut(int x,int y)
{
//  printf("cut %d %d\n",x,y);
makeroot(x);
access(y);
splay(y);
ch[y][0]=fa[x]=0;
//  update(x);update(y);
}

int m,n,a[maxn];

int main()
{
n=read(); for (int i=1;i<=n;++i) a[i]=read(),link(i,min(n+1,a[i]+i));
m=read();
while (m--)
{
int opt,x,y;
opt=read();x=read(); x++;
switch(opt)
{
case 1:
//              x=read();x++;
makeroot(n+1);
access(x);
splay(x);
printf("%d\n",siz[x]-1);
break;
case 2:
//              x=read();x++;
y=read();
cut(x,min(n+1,a[x]+x));
a[x]=y;
link(x,min(n+1,a[x]+x));
break;
}
}
}

  

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: