#2002. [Hnoi2010]Bounce 彈飛綿羊
Description
某天,發明了一種超級彈力裝置,爲了在他的綿羊朋友面前顯擺,他邀請小綿羊一起玩個遊戲。遊戲一開始,在地上沿着一條直線擺上個裝置,每個裝置設定初始彈力系數,當綿羊達到第i個裝置時,它會往後彈ki步,達到第個裝置,若不存在第個裝置,則綿羊被彈飛。綿羊想知道當它從第個裝置起步時,被彈幾次後會被彈飛。爲了使得遊戲更有趣,可以修改某個彈力裝置的彈力系數,任何時候彈力系數均爲正整數。
Input
第一行包含一個整數,表示地上有個裝置,裝置的編號從到,接下來一行有個正整數,依次爲那個裝置的初始彈力系數。第三行有一個正整數,接下來行每行至少有兩個數,若,你要輸出從出發被彈幾次後被彈飛,若則還會再輸入一個正整數,表示第個彈力裝置的係數被修改成。對於的數據,對於的數據
Output
對於每個的情況,你都要輸出一個需要的步數,佔一行。
Sample Input
4
1 2 1 1
3
1 1
2 1 1
1 1
Sample Output
2
3
題意
- 就是給你一個數組,假如你在一個位置被彈起來,那麼你將落到點處,兩種操作,一種是修改,另一種是查詢從位置開始跳跳幾次後位置第一次
題解
- 顯然做法無腦暴力,直接與連邊就行了,查詢的時候,這條實鏈的就是答案
- 網上有大佬用分塊做的,留坑待填
代碼
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
#define inf 0x3f3f3f3f
namespace LCT{
int ch[maxn][2],fa[maxn],mark[maxn];
int val[maxn],siz[maxn];
inline bool not_root(int x) {return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
inline int dir(int x) {return ch[fa[x]][1]==x;}
inline void add_mark(int x) {swap(ch[x][0],ch[x][1]);mark[x]^=1;} //將x這顆子樹翻轉
inline void push_down(int x) {
if(mark[x]) {
if(ch[x][0]) add_mark(ch[x][0]);
if(ch[x][1]) add_mark(ch[x][1]);
mark[x]=0;
}
}
inline void push_up(int x) {
siz[x]=1;
if(ch[x][0]) siz[x]+=siz[ch[x][0]];
if(ch[x][1]) siz[x]+=siz[ch[x][1]];
}
inline void pushall(int x) {
if(not_root(x)) pushall(fa[x]);
push_down(x);
}
inline void rotate(int x){
int y=fa[x],z=fa[y],k=dir(x);
if(ch[x][k^1]) fa[ch[x][k^1]]=y;ch[y][k]=ch[x][k^1];
if(not_root(y)) ch[z][dir(y)]=x;fa[x]=z;
ch[x][k^1]=y;fa[y]=x;
push_up(y);
}
inline void splay(int x,int goal=0) {
pushall(x);
while(not_root(x)) {
int y=fa[x],z=fa[y];
if(not_root(y)) {
if(dir(x)==dir(y)) rotate(y);
else rotate(x);
}
rotate(x);
}
push_up(x);
}
inline void access(int x) { //從原樹的根向x拉一條實鏈
for(int y=0;x;y=x,x=fa[x]) {
splay(x);ch[x][1]=y;push_up(x);
}
}
inline void make_root(int x) { //使x成爲原樹的根
access(x);splay(x);add_mark(x);
}
inline int find_root(int x) { //找到x在原樹中的根
access(x);splay(x);
while(ch[x][0]) push_down(x),x=ch[x][0];
splay(x);
return x;
}
inline void split(int x,int y) { //拉出一條x->y的實鏈,y爲splay根
make_root(x);access(y);splay(y);
}
inline bool link(int x,int y) { //連接x與y,若已經在同一顆原樹中,返回0
make_root(x);
if(find_root(y)==x) return 0;
fa[x]=y;return 1;
}
inline bool cut(int x,int y) {
make_root(x);
if(find_root(y)!=x||fa[y]!=x||ch[y][0]) return 0;
fa[y]=ch[x][1]=0;
push_up(x);
return 1;
}
};
using namespace LCT;
int n,m,opt,a[maxn],x,y;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
if(i+a[i]<=n) link(i,i+a[i]);
else link(i,n+1);
}
scanf("%d",&m);
for(int i=1;i<=m;i++) {
scanf("%d",&opt);
if(opt==1) {
scanf("%d",&x);x++;
split(x,n+1);
printf("%d\n",siz[n+1]-1);
}else {
scanf("%d %d",&x,&y);
x++;
if(x+a[x]<=n) cut(x,x+a[x]);
else cut(x,n+1);
a[x]=y;
if(x+a[x]<=n) link(x,x+a[x]);
else link(x,n+1);
}
}
}
~~