bzoj4196 软件包管理器

题意:给你一棵树。两种操作:1.将x点到根的链全部修改成1颜色。

2.将x点及其子树全部修改成0颜色。每次询问修改了多少个点的颜色。

 

标程:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=400005;
 4 int cnt,head[N],q,size[N],Dfn,fa[N],in[N],out[N],top[N],x,n,sum[N],tag[N];
 5 char s[15];
 6 struct node{int to,next;}num[N];
 7 void add(int x,int y)
 8 {num[++cnt].to=y;num[cnt].next=head[x];head[x]=cnt;}
 9 void dfs(int x)
10 {
11     size[x]=1;
12     for (int i=head[x];i;i=num[i].next)
13       if (num[i].to!=fa[x])
14       {
15            dfs(num[i].to);
16            size[x]+=size[num[i].to];
17       }
18 }
19 void dfs1(int x)
20 {
21     in[x]=++Dfn;
22     if (!top[x]) top[x]=x;
23     int t=0;
24     for (int i=head[x];i;i=num[i].next)
25       if (num[i].to!=fa[x]&&size[num[i].to]>size[t]) t=num[i].to;
26     if (t) top[t]=top[x],dfs1(t);
27     for (int i=head[x];i;i=num[i].next)
28       if (num[i].to!=fa[x]&&num[i].to!=t) dfs1(num[i].to);
29     out[x]=Dfn;
30 }
31 void down(int k,int l,int r)
32 {
33     if (tag[k]==1)
34     {
35         tag[k<<1]=1;tag[k<<1|1]=1;
36         sum[k<<1]=0;sum[k<<1|1]=0;
37         tag[k]=0;
38     }else
39     if (tag[k]==2)
40     {
41         tag[k<<1]=2;tag[k<<1|1]=2;int mid=(l+r)>>1;
42         sum[k<<1]=mid-l+1;sum[k<<1|1]=r-mid;
43         tag[k]=0;
44     }
45 }
46 int get_sum(int k,int l,int r,int L,int R,int op)
47 {
48     if (L<=l&&r<=R)
49     {
50         int t=sum[k];
51         if (!op) {sum[k]=0;tag[k]=1;return t;}
52         else {sum[k]=r-l+1;tag[k]=2;return (r-l+1)-t;}
53     }
54     int mid=(l+r)>>1,tmp=0;down(k,l,r);
55     if (L<=mid) tmp+=get_sum(k<<1,l,mid,L,R,op);
56     if (R>mid) tmp+=get_sum(k<<1|1,mid+1,r,L,R,op);
57     sum[k]=sum[k<<1]+sum[k<<1|1];
58     return tmp;
59 }
60 int qry(int x,int y)
61 {
62     int ans=0;
63     for (;top[x]!=top[y];x=fa[top[x]])
64     {
65         if (in[x]<in[y]) swap(x,y);
66         ans+=get_sum(1,1,n,in[top[x]],in[x],1);
67     }
68     if (in[x]>in[y]) swap(x,y);
69     ans+=get_sum(1,1,n,in[x],in[y],1);
70     return ans;
71 }
72 int main()
73 {
74     scanf("%d",&n);
75     for (int i=2;i<=n;i++) scanf("%d",&fa[i]),add(++fa[i],i);
76     dfs(1);dfs1(1);
77     scanf("%d",&q);
78     while (q--)
79     {
80         scanf("%s%d",s,&x);x++;
81         if (s[0]=='i') printf("%d\n",qry(1,x));
82         else printf("%d\n",get_sum(1,1,n,in[x],out[x],0));
83     }
84     return 0;
85 } 

 

易错点:1.注意标记会叠加,用一个标记数组,不要分两个。

 

题解:树链剖分+线段树

板子题吧。dfs序维护一下,再打个标记就好。

转载于:https://www.cnblogs.com/Scx117/p/8714955.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值