洛谷 3203 HNOI2010 BOUNCE 弹飞绵羊

【题解】

  这道题可以用Link-Cut Tree写。。

  首先建立一个虚拟节点N+1,$i$与$N+1$连边表示$i$被弹飞了

  对于修改操作,先$cut(i,min(n+1,i+k[i]))$,然后再$link(i,min(n+1,i+newk))$

  对于询问操作,先$makeroot(x)$,然后$splay(n+1)$,$access(n+1)$,那么答案就是$size[n+1]-1$

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define N (500010)
 4 #define ls (c[u][0])
 5 #define rs (c[u][1])
 6 using namespace std;
 7 int n,m,opt,k[N];
 8 inline int read(){
 9     int k=0,f=1; char c=getchar();
10     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
11     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
12     return k*f;
13 }
14 struct Link_Cut_Tree{
15     int top,c[N][2],fa[N],rev[N],size[N],q[N];
16     inline void pushdown(int u){
17         if(rev[u]) rev[ls]^=1,rev[rs]^=1,rev[u]^=1,swap(ls,rs);
18     }
19     inline void pushup(int u){
20         size[u]=1;
21         if(ls) size[u]+=size[ls];
22         if(rs) size[u]+=size[rs];
23     }
24     inline bool isroot(int u){
25         return c[fa[u]][0]!=u&&c[fa[u]][1]!=u;
26     }
27     inline bool which(int u){
28         return c[fa[u]][1]==u;
29     }
30     void rotate(int u){
31         int f=fa[u],gf=fa[f],wh=which(u);
32         if(!isroot(f)) c[gf][which(f)]=u;
33         fa[u]=gf; fa[f]=u; fa[c[u][wh^1]]=f;
34         c[f][wh]=c[u][wh^1]; c[u][wh^1]=f;
35         pushup(f); pushup(u);
36     }
37     void splay(int u){
38         q[top=1]=u;
39         for(int i=u;!isroot(i);i=fa[i]) q[++top]=fa[i];
40         for(int i=top;i;i--) pushdown(q[i]);
41         while(!isroot(u)){
42             if(!isroot(fa[u])) rotate(which(u)==which(fa[u])?fa[u]:u);
43             rotate(u);
44         }
45         pushup(u);
46     }
47     void access(int u){
48         for(int son=0;u;son=u,u=fa[u]) 
49             splay(u),c[u][1]=son,pushup(u);
50     }
51     void makeroot(int u){
52         access(u); splay(u); rev[u]^=1;
53     }
54     int find(int u){
55         access(u); splay(u);
56         while(ls) u=ls; splay(u); 
57         return u;
58     }
59     void split(int x,int y){
60         makeroot(x); access(y); splay(y);
61     }
62     void cut(int x,int y){
63         int xrt=find(x),yrt=find(y);
64         if(xrt!=yrt) return;
65         split(x,y);
66         if(c[y][0]==x) c[y][0]=0,fa[x]=0; 
67         pushup(y);
68     }
69     void link(int x,int y){
70         int xrt=find(x),yrt=find(y);
71         if(xrt==yrt) return;
72         makeroot(x); fa[x]=y;
73     }
74 }t;
75 int main(){
76     n=read();
77     for(int i=1;i<=n;i++) t.link(i,min(n+1,i+(k[i]=read())));    
78     m=read();
79     while(m--){
80         if((opt=read())==1){
81             int x=read()+1;
82             t.makeroot(x); t.access(n+1); t.splay(n+1);
83             printf("%d\n",t.size[n+1]-1);
84         }
85         else{
86             int x=read()+1,y=read();
87             if(x+y>n+1&&x+k[x]>n+1) continue;
88             t.cut(x,min(n+1,x+k[x]));
89             t.link(x,min(n+1,x+y));
90             k[x]=y;
91         }
92     }
93     return 0;
94 }
View Code

 

转载于:https://www.cnblogs.com/DriverLao/p/8270720.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值