P3203 [HNOI2010] 弹飞绵羊
P3203 [HNOI2010] 弹飞绵羊
题目描述
某天,Lostmonkey 发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。
游戏一开始,Lostmonkey 在地上沿着一条直线摆上
绵羊想知道当它从第
输入格式
第一行包含一个整数
接下来一行有
第三行有一个正整数
-
若
,你要输出从编号为 的装置出发被弹几次后被弹飞 -
若
,则还会再输入一个正整数 ,表示编号为 的弹力装置的系数被修改成 。
输出格式
对于每个
【数据范围】
对于
Solution:
LD再不放假让你飞起来
没想到这种题目还能用 LCT 做。我们思考一下每次重设弹力系数相当于什么:相当于断掉原来的边然后连一条 (x,x+k) 的边。所以我们开始时将每个点到对应的“着陆点”上就好了,然后注意一下因为弹飞显然是单向的,所有我们只需要让
然后这道看起来很模拟的 LCT 就被我们愉快的做完了。
Code:
#include<bits/stdc++.h> const int N=2e5+5; using namespace std; int n,m; struct LCT{ struct Tree{ int tag,ff,ch[2],siz; }t[N<<2]; int st[N]; #define ls t[x].ch[0] #define rs t[x].ch[1] #define fa t[x].ff inline bool isroot(int x) { return (t[fa].ch[0]==x||t[fa].ch[1]==x); } inline void pushup(int x) { t[x].siz=t[ls].siz+t[rs].siz+1; } inline void rotate(int x) { int y=fa,z=t[fa].ff,k=t[fa].ch[1]==x ? 1 : 0; if(isroot(y))t[z].ch[t[z].ch[1]==y]=x; t[x].ff=z; t[y].ch[k]=t[x].ch[!k]; if(t[x].ch[!k])t[t[x].ch[!k]].ff=y; t[x].ch[!k]=y; t[y].ff=x; pushup(y); } inline void splay(int x) { int y=x,z=0; while(isroot(x)) { y=fa,z=t[fa].ff; if(isroot(y)){rotate((t[y].ch[1]==x)==(t[z].ch[1]==y) ? y : x);} rotate(x); } pushup(x); } void access(int x) { int y=0; while(x) { splay(x);rs=y;pushup(x); y=x;x=fa; } } void link(int x,int y) { if(y<=n){t[x].ff=y;pushup(x);} } void cut(int x) // 这里是减去一个点 x { access(x),splay(x); t[x].ch[0]=t[ls].ff=0; } int query(int x) { access(x);splay(x); return t[x].siz; } }T; void work() { cin>>n; for(int i=1,tmp;i<=n;i++) { scanf("%d",&tmp); T.t[i].siz=1; T.link(i,i+tmp); } cin>>m; for(int i=1,opt,x,y;i<=m;i++) { scanf("%d%d",&opt,&x); x++; if(opt&1) { int ans=T.query(x); printf("%d\n",ans); } else { scanf("%d",&y); T.cut(x); T.link(x,x+y); } } } int main() { //freopen("bounce.in","r",stdin);freopen("bounce.out","w",stdout); work(); return 0; }