Link-Cut-Tree:【BZOJ2002】弹飞绵羊
2018-02-11 13:07
417 查看
题面:
[b]Description:[/b]某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上nn个装置,每个装置设定初始弹力系数kiki,当绵羊达到第ii个装置时,它会往前弹kiki步,达到第i+kii+ki个装置,若不存在第i+kii+ki个装置,则绵羊被弹飞。绵羊想知道当它从第ii个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
[b]Input:[/b]
第一行包含一个整数nn,表示地上有nn个装置,装置的编号从00到n−1n−1。
接下来一行有nn个正整数,依次为那nn个装置的初始弹力系数。
第三行有一个正整数mm。
接下来mm行每行至少有两个数i,ji,j,若i=1i=1,你要输出从jj出发被弹几次后被弹飞,若i=2i=2则还会再输入一个正整数kk,表示第jj个弹力装置的系数被修改成kk。
[b]Output:[/b]
对于每个i=1i=1的情况,你都要输出一个需要的步数,占一行。
[b]Sample Input:[/b]
4
1 2 1 1
3
1 1
2 1 1
1 1
[b]Sample Output:[/b]
2
3
[b]Hint:[/b]
对于20%的数据n,m≤10000n,m≤10000;
对于100%的数据n≤200000,m≤100000n≤200000,m≤100000;
1.如何建树?
若从这个点xx会被弹飞,连边(x,n+1)(x,n+1)若从这个点xx不会被弹飞,连边(x,x+kx)(x,x+kx)
根为n+1n+1
以样例做例子:
2.如何询问?
为蛤哈?
由于splay是按深度关键字排序,所以根的左子树的大小就是要被弹几次了呀。
3.如何修改?
把原来的边删了在连新的不就完了吗……代码:
#include<iostream> #include<cstdio> using namespace std; int ch[200002][2],fa[200002],siz[200002],num[200002],lazr[200002],cnt,n,q; inline unsigned rd(){ unsigned re=0; char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9'){ re=re*10+ch-'0'; ch=getchar(); } return re; } inline bool isroot(int bt){return ch[fa[bt]][0]!=bt&&ch[fa[bt]][1]!=bt;} inline int drct(int bt){return ch[fa[bt]][1]==bt;} inline void pushup(int bt){siz[bt]=siz[ch[bt][0]]+siz[ch[bt][1]]+1;} inline void reverse(int bt){swap(ch[bt][0],ch[bt][1]);lazr[bt]^=1;} inline void pd(int bt){ if(lazr[bt]){ if(ch[bt][0])reverse(ch[bt][0]); if(ch[bt][1])reverse(ch[bt][1]); lazr[bt]=0; } } inline void pushdown(int u){ if(!isroot(u))pushdown(fa[u]); pd(u); } inline void rotate(int u){ int f=fa[u],g=fa[f],c=drct(u); if(!isroot(f))ch[g][drct(f)]=u; fa[u]=g; ch[f][c]=ch[u][c^1]; if(ch[f][c])fa[ch[f][c]]=f; ch[u][c^1]=f; fa[f]=u; pushup(f); pushup(u); } void splay(int u){ pushdown(u); while(!isroot(u)){ if(!isroot(fa[u]))rotate(drct(fa[u])==drct(u)?fa[u]:u); rotate(u); } } void access(int u){ for(int v=0;u;v=u,u=fa[u]){ splay(u); ch[u][1]=v; pushup(u); } } void makeroot(int u){ access(u); splay(u); reverse(u); } void link(int a,int b){ makeroot(a); fa[a]=b; } void cut(int a,int b){ makeroot(a); access(b); splay(b); ch[b][0]=0; fa[a]=0; pushup(b); } int main(){ n=rd(); for(int i=1;i<=n;i++){ num[i]=rd(); siz[i]=1; } for(int i=1;i<=n;i++){ if(i+num[i]<=n)fa[i]=i+num[i]; else fa[i]=n+1; } q=rd(); for(int i=1;i<=q;i++){ int opt=rd(),x=rd()+1; if(opt==1){ makeroot(n+1); access(x); splay(x); printf("%d\n",siz[ch[x][0]]); }else{ int y=rd(); if(x+num[x]<=n)cut(x,x+num[x]); else cut(x,n+1); num[x]=y; if(x+num[x]<=n)link(x,x+num[x]); else link(x,n+1); } } }
相关文章推荐
- bzoj 2002: 弹飞绵羊 Link-Cut-Tree
- BZOJ 2002 弹飞绵羊 Link-Cut-Tree(LCT)
- BZOJ 2002 弹飞绵羊 Link-Cut-Tree(LCT)
- [bzoj2002][Hnoi2010]Bounce 弹飞绵羊 分块 Link-Cut-Tree
- [BZOJ2002] [HNOI2010] 弹飞绵羊 - Link-Cut-Tree (LCT)
- 【bzoj2002】[Hnoi2010]Bounce 弹飞绵羊 link-cut-tree
- bzoj2002Bounce 弹飞绵羊 动态树(Link-Cut-Tree)
- bzoj 2002 link cut tree(LCT)
- 2002: [Hnoi2010]Bounce 弹飞绵羊(link-cut-tree)
- bzoj 2002 LinkCutTree
- 【BZOJ-2555】SubString 后缀自动机 + LinkCutTree
- BZOJ-3669 魔法森林 Link-Cut-Tree
- [BZOJ 1036] [ZJOI2008] 树的统计Count 【Link Cut Tree】
- LinkCutTree试水之bzoj2049[Sdoi08]洞穴勘测题解
- BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊 ——Link-Cut Tree
- BZOJ 题目2002: [Hnoi2010]Bounce 弹飞绵羊(link cut tree)
- BZOJ 2594 Wc2006 水管局长数据加强版 Link-Cut-Tree
- bzoj 2049: [Sdoi2008]Cave 洞穴勘测 (link-cut-tree)
- [bzoj3664][Noi2014]魔法森林 Link-Cut-Tree 并查集
- 【BZOJ2049】[Sdoi2008]Cave 洞穴勘测 Link-Cut-Tree