您的位置:首页 > 其它

Link-Cut-Tree:【BZOJ2002】弹飞绵羊

2018-02-11 13:07 417 查看

题面:

[b]Description:[/b]

某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上nn个装置,每个装置设定初始弹力系数kiki,当绵羊达到第ii个装置时,它会往前弹kiki步,达到第i+kii+ki个装置,若不存在第i+kii+ki个装置,则绵羊被弹飞。绵羊想知道当它从第ii个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

[b]Input:[/b]

第一行包含一个整数nn,表示地上有nn个装置,装置的编号从00到n−1n−1。

接下来一行有nn个正整数,依次为那nn个装置的初始弹力系数。

第三行有一个正整数mm。

接下来mm行每行至少有两个数i,ji,j,若i=1i=1,你要输出从jj出发被弹几次后被弹飞,若i=2i=2则还会再输入一个正整数kk,表示第jj个弹力装置的系数被修改成kk。

[b]Output:[/b]

对于每个i=1i=1的情况,你都要输出一个需要的步数,占一行。

[b]Sample Input:[/b]

4


1 2 1 1


3


1 1


2 1 1


1 1


[b]Sample Output:[/b]

2


3


[b]Hint:[/b]

对于20%的数据n,m≤10000n,m≤10000;

对于100%的数据n≤200000,m≤100000n≤200000,m≤100000;

1.如何建树?

若从这个点xx会被弹飞,连边(x,n+1)(x,n+1)

若从这个点xx不会被弹飞,连边(x,x+kx)(x,x+kx)

根为n+1n+1

以样例做例子:



2.如何询问?



为蛤哈?

由于splay是按深度关键字排序,所以根的左子树的大小就是要被弹几次了呀。

3.如何修改?

把原来的边删了在连新的不就完了吗……

代码:

#include<iostream>
#include<cstdio>
using namespace std;
int ch[200002][2],fa[200002],siz[200002],num[200002],lazr[200002],cnt,n,q;
inline unsigned rd(){
unsigned re=0;
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
re=re*10+ch-'0';
ch=getchar();
}
return re;
}
inline bool isroot(int bt){return ch[fa[bt]][0]!=bt&&ch[fa[bt]][1]!=bt;}
inline int drct(int bt){return ch[fa[bt]][1]==bt;}
inline void pushup(int bt){siz[bt]=siz[ch[bt][0]]+siz[ch[bt][1]]+1;}
inline void reverse(int bt){swap(ch[bt][0],ch[bt][1]);lazr[bt]^=1;}
inline void pd(int bt){
if(lazr[bt]){
if(ch[bt][0])reverse(ch[bt][0]);
if(ch[bt][1])reverse(ch[bt][1]);
lazr[bt]=0;
}
}
inline void pushdown(int u){
if(!isroot(u))pushdown(fa[u]);
pd(u);
}
inline void rotate(int u){
int f=fa[u],g=fa[f],c=drct(u);
if(!isroot(f))ch[g][drct(f)]=u;
fa[u]=g;
ch[f][c]=ch[u][c^1];
if(ch[f][c])fa[ch[f][c]]=f;
ch[u][c^1]=f;
fa[f]=u;
pushup(f);
pushup(u);
}
void splay(int u){
pushdown(u);
while(!isroot(u)){
if(!isroot(fa[u]))rotate(drct(fa[u])==drct(u)?fa[u]:u);
rotate(u);
}
}
void access(int u){
for(int v=0;u;v=u,u=fa[u]){
splay(u);
ch[u][1]=v;
pushup(u);
}
}
void makeroot(int u){
access(u);
splay(u);
reverse(u);
}
void link(int a,int b){
makeroot(a);
fa[a]=b;
}
void cut(int a,int b){
makeroot(a);
access(b);
splay(b);
ch[b][0]=0;
fa[a]=0;
pushup(b);
}
int main(){
n=rd();
for(int i=1;i<=n;i++){
num[i]=rd();
siz[i]=1;
}
for(int i=1;i<=n;i++){
if(i+num[i]<=n)fa[i]=i+num[i];
else fa[i]=n+1;
}
q=rd();
for(int i=1;i<=q;i++){
int opt=rd(),x=rd()+1;
if(opt==1){
makeroot(n+1);
access(x);
splay(x);
printf("%d\n",siz[ch[x][0]]);
}else{
int y=rd();
if(x+num[x]<=n)cut(x,x+num[x]);
else cut(x,n+1);
num[x]=y;
if(x+num[x]<=n)link(x,x+num[x]);
else link(x,n+1);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: