某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
某天,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。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000
对于每个i=1的情况,你都要输出一个需要的步数,占一行。
方法一:分块
很巧妙的分块。
每个点记录跳出所在块的步数以及跳出去的位置,每次修改暴力修改所在块的信息。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 200005 using namespace std; int n,m,block; int a[maxn],num[maxn],f[maxn],p[maxn]; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int calc(int x) { int ret=0; for(;x;x=p[x]) ret+=f[x]; return ret; } int main() { n=read(); block=round(sqrt(n)); F(i,1,n) a[i]=read(),num[i]=(i-1)/block+1; D(i,n,1) { if (i+a[i]>n) f[i]=1,p[i]=0; else if (num[i]==num[i+a[i]]) f[i]=f[i+a[i]]+1,p[i]=p[i+a[i]]; else f[i]=1,p[i]=i+a[i]; } m=read(); while (m--) { int opt=read(),x=read()+1; if (opt==1) printf("%d\n",calc(x)); else { a[x]=read(); D(i,x,(num[x]-1)*block+1) { if (i+a[i]>n) f[i]=1,p[i]=0; else if (num[i]==num[i+a[i]]) f[i]=f[i+a[i]]+1,p[i]=p[i+a[i]]; else f[i]=1,p[i]=i+a[i]; } } } return 0; }
方法二:LCT
维护一下子树的大小,注意cut操作里要splay,因为x和y的父子关系不确定,否则会出错。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define N 200005 using namespace std; int n,m,nxt[N],st[N]; struct LCT { int ch[N][2],fa[N],sz[N];bool rev[N]; inline bool isroot(int x) { return (ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x); } inline void pushdown(int x) { if (!rev[x]) return; rev[ch[x][0]]^=1;rev[ch[x][1]]^=1; swap(ch[x][0],ch[x][1]); rev[x]=0; } inline void pushup(int x) { sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1; } void rotate(int x) { int y=fa[x],z=fa[y],l=ch[y][1]==x,r=l^1; if (!isroot(y)) ch[z][ch[z][1]==y]=x; fa[x]=z;fa[y]=x;fa[ch[x][r]]=y; ch[y][l]=ch[x][r];ch[x][r]=y; pushup(y);pushup(x); } void splay(int x) { int top=0;st[++top]=x; for(int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i]; D(i,top,1) pushdown(st[i]); while (!isroot(x)) { int y=fa[x],z=fa[y]; if (!isroot(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; t=x;x=fa[x]; } } inline void moveroot(int x) { access(x);splay(x);rev[x]^=1; } inline void link(int x,int y) { moveroot(x);fa[x]=y; } inline void cut(int x,int y) { moveroot(x);access(y);splay(y);ch[y][0]=fa[x]=0; } inline int query(int x) { moveroot(n+1);access(x);splay(x); return sz[ch[x][0]]; } }lct; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int main() { n=read(); F(i,1,n) { int x=read(); nxt[i]=lct.fa[i]=min(i+x,n+1); lct.sz[i]=1; } m=read(); while (m--) { int opt=read(),x=read()+1; if (opt==1) printf("%d\n",lct.query(x)); else { int y=read(),t=min(x+y,n+1); lct.cut(x,nxt[x]);lct.link(x,t);nxt[x]=t; } } return 0; }