Codeforces Round #502 (in memory of Leopoldo Taravilse, Div. 1 + Div. 2) G. The Tree

Posted wujiechao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #502 (in memory of Leopoldo Taravilse, Div. 1 + Div. 2) G. The Tree相关的知识,希望对你有一定的参考价值。

G. The Tree
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Abendsen assigned a mission to Juliana. In this mission, Juliana has a rooted tree with nn vertices. Vertex number 11 is the root of this tree. Each vertex can be either black or white. At first, all vertices are white. Juliana is asked to process qq queries. Each query is one of three types:

  1. If vertex vv is white, mark it as black; otherwise, perform this operation on all direct sons of vv instead.
  2. Mark all vertices in the subtree of vv (including vv) as white.
  3. Find the color of the ii-th vertex.
技术分享图片An example of operation "1 1" (corresponds to the first example test). The vertices 11 and 22 are already black, so the operation goes to their sons instead.

Can you help Juliana to process all these queries?

Input

The first line contains two integers nn and qq (2n1052≤n≤105, 1q1051≤q≤105) — the number of vertices and the number of queries.

The second line contains n?1n?1 integers p2,p3,,pnp2,p3,…,pn (1pi<i1≤pi<i), where pipi means that there is an edge between vertices ii and pipi.

Each of the next qq lines contains two integers titi and vivi (1ti31≤ti≤3, 1vin1≤vi≤n) — the type of the ii-th query and the vertex of the ii-th query.

It is guaranteed that the given graph is a tree.

Output

For each query of type 33, print "black" if the vertex is black; otherwise, print "white".


 

题意:给你一颗树,树上一开始点的颜色全是白色。然后有三种操作:1.把一个白色的点v染成黑色,如果该点v本就是黑色,则对他的所有直接子节点做操作1。2.将节点v的子树全部染成白色。3.查询节点v的颜色。对于每个操作3输出其颜色。

题解:我们要使其在一个尽量平均的时间内进行求解,就需要将其改造成一个相对平衡的树,那我们就考虑用树链刨分对这颗树进行分解。我们发觉每个操作1对应使该点所在的一条重链所对应的区间黑色区间右端点后移一位,其他影响到的重链也后移一位。因此我们查询点v是否为黑色,就看从根到v点的所有链对应的区间上,任何黑色区间右端点位移位置是否超过该点v。我们对线段树维护两个值,一个是端点对应区间剩余白色点的个数leaf(可为负数,即透支后面的链的白色点数),另一个是对应区间中最靠右侧的黑色区间的右端点超出该区间右端点距离(也就是我们上文说到的对其他重链的影响长度)execr,一开始是-1因为右端点还是白色。剩余白色点的转移就是子区间白色点数相加,而第二个维护量execr(即向区间右端点后边区间的影响长度)的转移则是max(右子区间execr,左子区间execr-右子区间leaf)。这样我们查询的时候就能通过该点向后影响长度来查询该点是不是被染成黑色。>=0就是被染色了,-1则是未染色。对于操作1,直接对对应的线段树上的单点v的区间的execr++,leaf--。对于操作3,我们将根节点到节点v的所有区间连起来,算算execr是不是>-1,若是则染色了。对于操作2,我们则直接把所有对应的区间清0,即leaf为区间点数,execr为-1。为了防止v的祖先节点对v子树区间的影响,我们对v做操作3查询超出长度k,若>-1,则反向对v点做操作1(k+1)次,即execr-=(k+1),leaf+=(k+1)。

技术分享图片
  1 #include<bits/stdc++.h>
  2 #define clr(x) memset(x,0,sizeof(x))
  3 #define clr_1(x) memset(x,-1,sizeof(x))
  4 #define INF 0x3f3f3f3f
  5 #define LL long long
  6 #define pb push_back
  7 #define ls(i) (i<<1)
  8 #define rs(i) (i<<1|1)
  9 #define mp make_pair
 10 #define fi first
 11 #define se second
 12 #define mod 1000000007
 13 using namespace std;
 14 const int N=2e5+100;
 15 vector<int> e[N];
 16 int fa[N];
 17 struct seg
 18 {
 19     int l,r,execr,leaf;
 20     bool tag;
 21 }tree[N<<2];
 22 int n,m,k,q;
 23 int t,v;
 24 void pushup(int i)
 25 {
 26     tree[i].leaf=tree[i<<1].leaf+tree[i<<1|1].leaf;
 27     tree[i].execr=max(tree[i<<1|1].execr,tree[i<<1].execr-tree[i<<1|1].leaf);
 28     return ;
 29 }
 30 void init(int i,int l,int r)
 31 {
 32     tree[i]=(seg){l,r,-1,1,false};
 33     if(l==r)
 34         return ;
 35     int mid=l+r>>1;
 36     init(i<<1,l,mid);
 37     init(i<<1|1,mid+1,r);
 38     pushup(i);
 39     return ;
 40 }
 41 int top[N],son[N],pre[N],las[N],stot[N],dep[N];
 42 int tot;
 43 void dfs1(int u,int f,int deep)
 44 {
 45     stot[u]=1;
 46     dep[u]=deep;
 47     fa[u]=f;
 48     for(auto p:e[u])
 49     {
 50         if(p==f) continue;
 51         dfs1(p,u,deep+1);
 52         stot[u]+=stot[p];
 53         if(son[u]==0 || stot[son[u]]<stot[p])
 54             son[u]=p;
 55     }
 56     return ;
 57 }
 58 void dfs2(int u,int tp)
 59 {
 60     pre[u]=++tot;
 61     top[u]=tp;
 62     if(son[u]) dfs2(son[u],tp);
 63     for(auto p:e[u])
 64     {
 65         if(p==son[u] || p==fa[u])
 66             continue;
 67         dfs2(p,p);
 68     }
 69     las[u]=tot;
 70     return ;
 71 }
 72 void pushdown(int i)
 73 {
 74     if(tree[i].l!=tree[i].r)
 75     {
 76         tree[i<<1].tag=tree[i<<1|1].tag=1;
 77         tree[i<<1].leaf=tree[i<<1].r-tree[i<<1].l+1,tree[i<<1].execr=-1;
 78         tree[i<<1|1].leaf=tree[i<<1|1].r-tree[i<<1|1].l+1,tree[i<<1|1].execr=-1;
 79     }
 80     tree[i].tag=0;
 81     return ;
 82 }
 83 void update(int i,int l,int r,int val)
 84 {
 85     if(tree[i].l>=l && tree[i].r<=r)
 86     {
 87         if(val==INF)//都是区间修改
 88             tree[i].leaf=tree[i].r-tree[i].l+1,tree[i].execr=-1,tree[i].tag=1;
 89         else
 90             tree[i].leaf-=val,tree[i].execr+=val,tree[i].tag=0;//都是单点修改
 91         return ;
 92     }
 93     if(tree[i].tag) pushdown(i);
 94     int mid=tree[i].l+tree[i].r>>1;
 95     if(l<=mid) update(i<<1,l,r,val);
 96     if(r>mid) update(i<<1|1,l,r,val);
 97     pushup(i);
 98     return ;
 99 }
100 struct ret{
101     int execr,leaf;
102 };
103 ret operator + (const ret &a,const ret &b)
104 {
105     ret c;
106     c.leaf=a.leaf+b.leaf;
107     c.execr=max(b.execr,a.execr-b.leaf);
108     return c;
109 }
110 ret query(int i,int l,int r)
111 {
112     if(tree[i].l>=l && tree[i].r<=r)
113         return (ret){tree[i].execr,tree[i].leaf};
114     if(tree[i].tag) pushdown(i);
115     int mid=tree[i].l+tree[i].r>>1;
116     ret retur=(ret){-INF,0};
117     if(r>mid) retur=query(i<<1|1,l,r)+retur;
118     if(l<=mid) retur=query(i<<1,l,r)+retur;
119     return retur;
120 }
121 int que(int x)
122 {
123     int tx=top[x];
124     ret retur=(ret){-INF,0},per;
125     while(tx!=1)
126     {
127         per=query(1,pre[tx],pre[x]);
128         retur=per+retur;
129         x=fa[tx],tx=top[x];
130     }
131     per=query(1,pre[tx],pre[x]);
132     retur=per+retur;
133     return retur.execr;
134 }
135 int main()
136 {
137     ios::sync_with_stdio(false);
138     cin.tie(0);
139     cout.tie(0);
140     cin>>n>>q;
141     for(int i=2;i<=n;i++)
142     {
143         cin>>v;
144         e[v].pb(i);
145         e[i].pb(v);
146     }
147     init(1,1,n);
148     dfs1(1,1,1);
149     dfs2(1,1);
150     for(int i=1;i<=q;i++)
151     {
152         cin>>t>>v;
153         if(t==1)
154             update(1,pre[v],pre[v],1);
155         else if(t==2)
156         {
157             update(1,pre[v],las[v],INF);
158             t=que(v);
159             if(t>-1)
160                 update(1,pre[v],pre[v],-(t+1));
161         }
162         else if(t==3)
163         {
164             t=que(v);
165             cout<<(t>-1?"black":"white")<<endl;
166         }
167     }
168     return 0;
169 }
View Code

 

以上是关于Codeforces Round #502 (in memory of Leopoldo Taravilse, Div. 1 + Div. 2) G. The Tree的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #502 D. The Wu(状压预处理)

[Codeforces Round49F] Session in BSU

Codeforces Round #494 (Div. 3)爆炸记

Codeforces Round #313 A. Currency System in Geraldion

Educational Codeforces Round 7 E. Ants in Leaves(DFS+贪心)

codeforces Educational Codeforces Round 9 E - Thief in a Shop