BZOJ2002 [Hnoi2010]Bounce 弹飞绵羊
作者:互联网
题意
某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
分析
参照FlashHu的题解。
首先分析一下题意。对于每个弹力装置,有且仅有一个位置可以弹到。把这样的一种关系可以视作边。
然后,每个装置一定会往后弹,这不就代表不存在环么?
于是,一个森林的模型被我们建出来了。
考虑到有修改弹力值的操作,也就是要断边和连边,于是用LCT维护。
每一个点向它弹到的位置连边。如果被弹飞了,那么这条边就不存在。
查询弹飞的步数,就是查询该点到其所属原树中根节点的路径的size。
注意此题的一些特性。我们并不需要查询或者更改指定路径(x−y)的信息。
也就是说,我们根本不需要换根!
原来需要换根的split,link,cut操作,我们可以根据题目特性适当调整一下。
- 查询原本需要split,我们直接access(x),splay(x),输出x的size。
- 连边原本需要link,题目保证了是一棵树,我们直接改x的父亲,连轻边。
- 断边原本需要cut,然而我们确定其父亲的位置,access(x),splay(x)后,x的父亲一定在x的左子树中(LCT总结中的性质1),直接双向断开连接。
然后我们发现,程序一下子少了一堆函数(pushdown,makeroot,findroot,split,link,cut)
代码少,常数小,何乐而不为?
时间复杂度\(O(n+m\log n)\)
代码
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;
rg char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x){
return x=read<T>();
}
typedef long long ll;
co int N=2e5+1;
int f[N],c[N][2],s[N];
#define R register int
#define I inline void
bool nroot(int x){
return c[f[x]][0]==x||c[f[x]][1]==x;
}
void pushup(int x){
s[x]=s[c[x][0]]+1+s[c[x][1]];
}
void rotate(int x){
int y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
if(nroot(y)) c[z][c[z][1]==y]=x;c[x][!k]=y,c[y][k]=w;
if(w) f[w]=y;f[y]=x,f[x]=z;
pushup(y);
}
void splay(int x){
int y,z;
while(nroot(x)){
y=f[x],z=f[y];
if(nroot(y)) rotate(c[y][0]==x^c[z][0]==y?x:y);
rotate(x);
}
pushup(x);
}
void access(int x){
for(int y=0;x;x=f[y=x])
splay(x),c[x][1]=y,pushup(x);
}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
int n=read<int>();
for(int i=1,k;i<=n;++i){
s[i]=1,read(k);
if(i+k<=n) f[i]=i+k;
}
int m=read<int>();
for(int o,i,k;m--;){
read(o);
if(o==1){
read(i),++i;
access(i),splay(i);
printf("%d\n",s[i]);
}
else{
read(i),++i,read(k);
access(i),splay(i);
c[i][0]=f[c[i][0]]=0;
if(i+k<=n) f[i]=i+k;
pushup(i);
}
}
return 0;
}
标签:ch,int,BZOJ2002,Bounce,splay,read,弹力,Hnoi2010,装置 来源: https://www.cnblogs.com/autoint/p/10413445.html