【bzoj2002】 Hnoi2010—Bounce 弹飞绵羊
http://www.lydsy.com/JudgeOnline/problem.php?id=2002 (题目链接)
题意
数轴上${n}$个点,每个点有一个权值${a_i}$,如果到达这个点,接下来会到达第${i+a_i}$个点。2个操作,修改某个权值,查询从一个点出发要经过多少点才能离开序列。
Solution
lct的很多细节还是没有很明白啊。
对于cut,如果我们知道cut的是x与x的祖先,那么就没有必要换根了。
对于link,我们读入边的时候,其实想知道的只是每个点的父亲是谁。如果是无向边,必须link,因为你不知道读入的两个点的关系,而有向边的话就可以直接对fa数组赋值了。
细节
好像没什么。。
代码
// bzoj2002 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #define LL long long #define inf 2147483647 #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; const int maxn=200010; int size[maxn],tr[maxn][2],fa[maxn]; int n,m; void pushup(int x) { size[x]=size[tr[x][0]]+size[tr[x][1]]+1; } void rotate(int x) { int y=fa[x],z=fa[y],l,r; l=tr[y][1]==x;r=l^1; if (tr[z][0]==y || tr[z][1]==y) tr[z][tr[z][1]==y]=x; fa[x]=z;fa[y]=x;fa[tr[x][r]]=y; tr[y][l]=tr[x][r];tr[x][r]=y; pushup(y);pushup(x); } void splay(int x) { while (tr[fa[x]][0]==x || tr[fa[x]][1]==x) { int y=fa[x],z=fa[y]; if (tr[z][0]==y || tr[z][1]==y) { if (tr[z][0]==y ^ tr[y][0]==x) rotate(x); else rotate(y); } rotate(x); } } void access(int x) { for (int y=0;x;y=x,x=fa[x]) splay(x),tr[x][1]=y,pushup(x); } void link(int x,int y) { access(x);splay(x); tr[x][0]=fa[tr[x][0]]=0;pushup(x); fa[x]=y; } int main() { scanf("%d",&n); for (int x,i=1;i<=n;i++) { scanf("%d",&x); fa[i]=min(n+1,i+x); } scanf("%d",&m); for (int op,x,k,i=1;i<=m;i++) { scanf("%d%d",&op,&x);x++; if (op==1) { access(x);splay(x);printf("%d\n",size[x]-1); } if (op==2) { scanf("%d",&k); link(x,min(n+1,x+k)); } } return 0; }
This passage is made by MashiroSky.