洛谷P3203 [HNOI2010]彈飛綿羊【LCT】
題目描述
某天,Lostmonkey發明了一種超級彈力裝置,為了在他的綿羊朋友面前顯擺,他邀請小綿羊一起玩個遊戲。遊戲一開始,Lostmonkey在地上沿著一條直線擺上n個裝置,每個裝置設定初始彈力系數ki,當綿羊達到第i個裝置時,它會往後彈ki步,達到第i+ki個裝置,若不存在第i+ki個裝置,則綿羊被彈飛。綿羊想知道當它從第i個裝置起步時,被彈幾次後會被彈飛。為了使得遊戲更有趣,Lostmonkey可以修改某個彈力裝置的彈力系數,任何時候彈力系數均為正整數。
輸入格式:
第一行包含一個整數n,表示地上有n個裝置,裝置的編號從0到n-1。
接下來一行有n個正整數,依次為那n個裝置的初始彈力系數。
第三行有一個正整數m,
接下來m行每行至少有兩個數i、j,若i=1,你要輸出從j出發被彈幾次後被彈飛,若i=2則還會再輸入一個正整數k,表示第j個彈力裝置的系數被修改成k。
輸出格式:
對於每個i=1的情況,你都要輸出一個需要的步數,占一行。
輸入樣例
4
1 2 1 1
3
1 1
2 1 1
1 1
輸出樣例
2
3
說明
對於20%的數據n,m<=10000,對於100%的數據n<=200000,m<=100000
********************************
題目分析:
這題的思路饒了點彎,但確實巧妙
將每個點標號+1以便操作
對每個彈簧i
若$i+ki<=n$,那麽我們就在i與i+ki之間連邊
若$i+ki>n$,我們向一個虛點n+1連邊,表示被彈飛
那麽從j出發彈幾次會彈飛
就轉化為從j到n+1的路徑經過幾個結點
那麽我們只要給每個結點維護一個size[]就可以查詢了
具體為先makeroot(x)
在access(n+1),splay(n+1)
這時在splay中就是所求路徑
直接輸出size[n+1]-1
對於修改ki
我們先斷開原來i到i+ki的邊
再按上述方式對新的ki重新連邊
**********************
#include<iostream> #include<vector> #include<algorithm> #include<queue> #include<cstring> #include<cstdio> using namespace std; int read() { int f=1,x=0; char ss=getchar(); while(ss<‘0‘||ss>‘9‘){if(ss==‘-‘)f=-1;ss=getchar();} while(ss>=‘0‘&&ss<=‘9‘){x=x*10+ss-‘0‘;ss=getchar();} return f*x; } const int maxn=500010; int n,m; int v[maxn],size[maxn]; int ch[maxn][2],fa[maxn]; int lzy[maxn]; int st[maxn]; void update(int x) { size[x]=size[ch[x][0]]+size[ch[x][1]]+1; } void push(int x) { if(!lzy[x]) return; swap(ch[x][0],ch[x][1]); lzy[ch[x][0]]^=1; lzy[ch[x][1]]^=1; lzy[x]=0; } int isrt(int x) { return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; } void rotate(int x) { int y=fa[x],z=fa[y]; int d=(ch[y][0]==x); if(!isrt(y)) { if(ch[z][0]==y) ch[z][0]=x; else ch[z][1]=x; } fa[y]=x; fa[ch[x][d]]=y; fa[x]=z; ch[y][d^1]=ch[x][d]; ch[x][d]=y; update(y); update(x); } void splay(int x) { int top=0; st[++top]=x; for(int i=x;!isrt(i);i=fa[i]) st[++top]=fa[i]; while(top) push(st[top--]); while(!isrt(x)) { int y=fa[x],z=fa[y]; if(!isrt(y)) { if((ch[y][0]==x)^(ch[z][0]==y)) rotate(x); else rotate(y); } rotate(x); } } void access(int x) { int t=0; while(x) { splay(x); ch[x][1]=t; update(x); t=x; x=fa[x]; } } void mkrt(int x) { access(x); splay(x); lzy[x]^=1; } void match(int x,int y) { mkrt(x),fa[x]=y; } void cut(int x,int y) { mkrt(x); access(y); splay(y); fa[x]=0; ch[y][0]=0; update(y); } void get() { int x=read()+1; mkrt(x); access(n+1); splay(n+1); printf("%d\n",size[n+1]-1); } void change() { int x=read()+1; if(x+v[x]<=n) cut(x,x+v[x]); else cut(x,n+1); v[x]=read(); if(x+v[x]<=n) match(x,x+v[x]); else match(x,n+1); } int main() { n=read(); for(int i=1;i<=n+1;++i)size[i]=1; for(int i=1;i<=n;++i) { v[i]=read(); if(i+v[i]<=n) match(i,i+v[i]); else match(i,n+1); } m=read(); while(m--) { int k=read(); if(k==1) get(); else change(); } return 0; }
洛谷P3203 [HNOI2010]彈飛綿羊【LCT】