1. 程式人生 > >【刷題】BZOJ 2002 [Hnoi2010]Bounce 彈飛綿羊

【刷題】BZOJ 2002 [Hnoi2010]Bounce 彈飛綿羊

roo double ces AR body ++i () 刷題 min

Description

某天,Lostmonkey發明了一種超級彈力裝置,為了在他的綿羊朋友面前顯擺,他邀請小綿羊一起玩個遊戲。遊戲一開始,Lostmonkey在地上沿著一條直線擺上n個裝置,每個裝置設定初始彈力系數ki,當綿羊達到第i個裝置時,它會往後彈ki步,達到第i+ki個裝置,若不存在第i+ki個裝置,則綿羊被彈飛。綿羊想知道當它從第i個裝置起步時,被彈幾次後會被彈飛。為了使得遊戲更有趣,Lostmonkey可以修改某個彈力裝置的彈力系數,任何時候彈力系數均為正整數。

Input

第一行包含一個整數n,表示地上有n個裝置,裝置的編號從0到n-1,接下來一行有n個正整數,依次為那n個裝置的初始彈力系數。第三行有一個正整數m,接下來m行每行至少有兩個數i、j,若i=1,你要輸出從j出發被彈幾次後被彈飛,若i=2則還會再輸入一個正整數k,表示第j個彈力裝置的系數被修改成k。對於20%的數據n,m<=10000,對於100%的數據n<=200000,m<=100000

Output

對於每個i=1的情況,你都要輸出一個需要的步數,占一行。

Sample Input

4
1 2 1 1
3
1 1
2 1 1
1 1

Sample Output

2
3

Solution

轉換成LCT的思路還是巧妙的
我們把每個點要彈到的點向這個點連一條邊,因為一個點彈到的點是固定的,所以這樣連完後的圖是一棵樹
然後我們發現對於題目的兩個操作
第一個查詢操作,就是求樹上一條鏈的長度,也可以說是大小
第二個修改操作,就是把樹上的一條邊斷掉,然後重連一條邊
這兩個東西,一看就可以用LCT
然後就LCT了
一開始我是照著板子打了一個LCT,但是T掉了
因為正宗的LCT對於這道題有很多多余的操作

我們只要access,splay,nroot,rotate和pushup,當然也可以說還有一個簡易的link
因為刪邊一定存在,所以可以直接刪除,而刪邊加邊的點是同一個點,兩個操作簡化後和在一起就可以了
其實這道題LCT維護的是一個森林,這個有點難理解

#include<bits/stdc++.h>
#define ll long long
#define db double
#define ld long double
#define lc(x) ch[(x)][0]
#define rc(x) ch[(x)][1]
const int MAXN=200000+10;
int n,m,A[MAXN];
struct
LCT{ int ch[MAXN][2],fa[MAXN],sum[MAXN]; inline void init() { memset(ch,0,sizeof(ch)); memset(fa,0,sizeof(fa)); memset(sum,0,sizeof(sum)); } inline bool nroot(int x) { return lc(fa[x])==x||rc(fa[x])==x; } inline void pushup(int x) { sum[x]=sum[lc(x)]+sum[rc(x)]+1; } inline void rotate(int x) { int f=fa[x],p=fa[f],c=(rc(f)==x); if(nroot(f))ch[p][rc(p)==f]=x; fa[ch[f][c]=ch[x][c^1]]=f; fa[ch[x][c^1]=f]=x; fa[x]=p; pushup(f); pushup(x); } inline void splay(int x) { for(register int y=fa[x];nroot(x);rotate(x),y=fa[x]) if(nroot(y))rotate((lc(y)==x)==(lc(fa[y]==y))?y:x); pushup(x); } inline void access(int x) { for(register int y=0;x;x=fa[y=x])splay(x),rc(x)=y,pushup(x); } }; LCT T; template<typename T> inline void read(T &x) { T data=0,w=1; char ch=0; while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar(); x=data*w; } template<typename T> inline void write(T x,char c='\0') { if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); if(c!='\0')putchar(c); } template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);} template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);} template<typename T> inline T min(T x,T y){return x<y?x:y;} template<typename T> inline T max(T x,T y){return x>y?x:y;} int main() { read(n); for(register int i=1;i<=n;++i)read(A[i]); T.init(); for(register int i=1;i<=n;++i) if(A[i]+i<=n)T.fa[i]=A[i]+i; read(m); while(m--) { int opt; read(opt); if(opt==1) { int pos; read(pos); pos++; T.access(pos);T.splay(pos); write(T.sum[pos],'\n'); } if(opt==2) { int pos,k; read(pos);read(k); pos++;A[pos]=k; T.access(pos);T.splay(pos); T.lc(pos)=T.fa[T.lc(pos)]=0; if(A[pos]+pos<=n)T.fa[pos]=A[pos]+pos; T.pushup(pos); } } return 0; }

【刷題】BZOJ 2002 [Hnoi2010]Bounce 彈飛綿羊