1. 程式人生 > >[bzoj] 2002 彈飛綿羊 || LCT

[bzoj] 2002 彈飛綿羊 || LCT

ces 簡單 www source com push pushd bzoj 每次

原題

簡單的LCT練習題。
我們發現對於一個位置x,他只能跳到位置x+k,也就是唯一的父親去。加入我們將彈飛的綿羊定義為跳到了n+1,那麽這就形成了一棵樹。而因為要修改k,所以這顆樹是動態連邊的,那麽LCT就可以解決了。
至於詢問,我們把n+1變成根,然後access(x)將x到n+1的路徑變為實路徑,splay(x),因為每次是向父親彈,所以sze[ls[x]]即為答案。
//想知道為什麽不是sze[x]-1

AC代碼:

#include<cstdio>
#include<algorithm>
#define N 200010
#define which(u) (ls[fa[(u)]]==(u))
#define isroot(u) (!fa[(u)] || (ls[fa[(u)]]!=(u) && rs[fa[u]]!=(u))) using namespace std; int n,m,fa[N],ls[N],rs[N],a[N],sze[N]; bool rev[N]; char s[20]; void update(int x) { sze[x]=1; if (ls[x]) sze[x]+=sze[ls[x]]; if (rs[x]) sze[x]+=sze[rs[x]]; } void rotate(int u) { int v=fa[u],w=fa[v],b=which(u)?rs[u]:ls[u]; if
(!isroot(v)) (which(v)?ls[w]:rs[w])=u; which(u)?(ls[v]=b,rs[u]=v):(rs[v]=b,ls[u]=v); fa[u]=w,fa[v]=u; if (b) fa[b]=v; if (v) update(v); if (u) update(u); } void pushdown(int u) { if (!rev[u]) return ; rev[ls[u]]^=1; rev[rs[u]]^=1; swap(ls[u],rs[u]); rev[u]=0; } void
splay(int u) { static int stk[N],top; stk[top=1]=u; while (!isroot(stk[top])) stk[top+1]=fa[stk[top]],top++; while (top) pushdown(stk[top--]); while (!isroot(u)) { if (!isroot(fa[u])) { if (which(u)==which(fa[u])) rotate(fa[u]); else rotate(u); } rotate(u); } } void access(int u) { int v=0; while (u) { splay(u); rs[u]=v; v=u; u=fa[u]; } } void makeroot(int u) { access(u); splay(u); rev[u]^=1; } void link(int u,int v) { makeroot(v); fa[v]=u; } void cut(int u,int v) { makeroot(u); access(v); splay(v); ls[v]=fa[u]=0; } int query(int x) { makeroot(n+1); access(x); splay(x); return sze[ls[x]]; } int main() { scanf("%d",&n); for (int i=1,x;i<=n;i++) { scanf("%d",&x); a[i]=(i+x<=n)?i+x:n+1; fa[i]=a[i]; sze[i]=1; } sze[n+1]=1; scanf("%d",&m); while (m--) { int op,x,y; scanf("%d%d",&op,&x); ++x; if (op==1) printf("%d\n",query(x)); else { scanf("%d",&y); cut(x,a[x]); a[x]=(x+y<=n)?x+y:n+1; link(x,a[x]); } } return 0; }

[bzoj] 2002 彈飛綿羊 || LCT