[BZOJ 3637]Query on a tree VI

偶然看见了这题,觉得自己 QTREE、COT 什么的都没有刷过的真是弱爆了……

一道思路很巧妙的题,终于是在约大爷的耐心教导下会了,真是太感谢约大爷了。

这题显然是树链剖分,但是链上维护的东西很恶心。其核心思想是找到一个相连的最浅同色节点,那么我只要维护每个点的子树中与他相连的点的数量即可

用 f[c][u] 表示在 u 的子树中与 u 相连 (假设 u 无色) 且颜色为 c 的点数

查询直接算出与 u 相连的最浅同色节点 a,ans=f[c[u]][a]

考虑修改,我们发现每次 u 被反转,影响到的点是 father[u] 一直往上,直到根或一个异色点(PS. 最浅异色 a 的 f[ ][a] 也会被改),而且他们的 f[][] 都是加一个数或减一个数

(PS2. father[u] 的 f[][] 会被改两次,因为 u 的颜色变了,导致 f[0][father[u]]、f[1][father[u]] 都在变)

区间修改,单点查询,于是用树状树组搞搞救过了

至于找到一个相连的最浅同色节点,可用线段树——比如:三叉神经树的做法

也可以在每条链上暴力挂 3 个 map 神马的……

反正是好 YY de 啦~

  1 #include <cstdio>
  2 #include <cstring>
  3 const int sizeOfPoint=100001;
  4
  5 inline int getint();
  6 inline void putint(int);
  7
  8 int n, m;
  9 int f[sizeOfPoint], d[sizeOfPoint], s[sizeOfPoint];
 10 int p[20][sizeOfPoint];
 11 int num, idx[sizeOfPoint], son[sizeOfPoint], top[sizeOfPoint];
 12 bool c[sizeOfPoint];
 13
 14 struct node
 15 {
 16     int ll, rr;
 17     bool lc, rc;
 18     int len;
 19     node * l, * r;
 20     inline void maintain();
 21 };
 22 node * t;
 23 node memory_node[sizeOfPoint<<2], * port_node=memory_node;
 24 inline node * newnode(int, int);
 25 node * build(int, int);
 26 void update(node * , int);
 27 int query(node * , int, int);
 28
 29 int sum[2][sizeOfPoint];
 30 inline int lowbit(int);
 31 inline void update(int * , int, int, int);
 32 inline int query(int * , int);
 33
 34 struct edge {int point; edge * next;};
 35 edge memory_edge[sizeOfPoint<<1], * port_edge=memory_edge;
 36 edge * e[sizeOfPoint];
 37 inline edge * newedge(int, edge * );
 38 inline void link(int, int);
 39 inline int lg(int);
 40 void dfs_tree(int);
 41 void dfs_chain(int, int);
 42 inline int anc(int, int);
 43 inline void update(bool, int, int, int);
 44 inline int query(int);
 45
 46 int main()
 47 {
 48     n=getint();
 49     for (int i=1;i<n;i++)
 50     {
 51         int u=getint(), v=getint();
 52         link(u, v);
 53     }
 54
 55     memset(d, 0xFF, sizeof(d)); d[1]=0;
 56     dfs_tree(1);
 57     dfs_chain(1, 1);
 58     t=build(1, n);
 59     for (int i=1;i<=n;i++) update(sum[0], idx[i], idx[i], s[i]-1);
 60
 61     m=getint();
 62     for (int i=1;i<=m;i++)
 63     {
 64         int o=getint(), u=getint();
 65
 66         if (o==0)
 67         {
 68             int f=query(u);
 69             putint(1+query(sum[c[f]], idx[f]));
 70         }
 71         else if (u==1) c[u]^=1;
 72         else
 73         {
 74             int s=query(sum[c[u]], idx[u])+1;
 75             c[u]^=1;
 76             update(t, idx[u]);
 77
 78             if (c[u]==c[f[u]])
 79             {
 80                 update(sum[!c[u]], idx[f[u]], idx[f[u]], -s);
 81                 int a=query(f[u]);
 82                 s=query(sum[c[u]], idx[u])+1;
 83                 if (a==1) update(c[u], f[u], a, s);
 84                 else update(c[u], f[u], f[a], s);
 85             }
 86             else
 87             {
 88                 int a=query(f[u]);
 89                 if (a==1) update(!c[u], f[u], a, -s);
 90                 else update(!c[u], f[u], f[a], -s);
 91                 s=query(sum[c[u]], idx[u])+1;
 92                 update(sum[c[u]], idx[f[u]], idx[f[u]], s);
 93             }
 94         }
 95     }
 96
 97     return 0;
 98 }
 99 inline int getint()
100 {
101     register int num=0;
102     register char ch;
103     do ch=getchar(); while (ch<‘0‘ || ch>‘9‘);
104     do num=num*10+ch-‘0‘, ch=getchar(); while (ch>=‘0‘ && ch<=‘9‘);
105     return num;
106 }
107 inline void putint(int num)
108 {
109     char stack[11];
110     register int top=0;
111     if (num==0) stack[top=1]=‘0‘;
112     for ( ;num;num/=10) stack[++top]=num%10+‘0‘;
113     for ( ;top;top--) putchar(stack[top]);
114     putchar(‘\n‘);
115 }
116
117 inline void node::maintain()
118 {
119     lc=l->lc; rc=r->rc;
120     len=r->len;
121     if (len==r->rr-r->ll+1 && l->rc==r->lc) len+=l->len;
122 }
123 inline node * newnode(int ll, int rr)
124 {
125     node * ret=port_node++;
126     ret->ll=ll; ret->rr=rr;
127     ret->l=ret->r=NULL;
128     return ret;
129 }
130 node * build(int ll, int rr)
131 {
132     node * t=newnode(ll, rr);
133     if (ll==rr) t->lc=t->rc=c[ll], t->len=1;
134     else
135     {
136         int m=(ll+rr)>>1;
137         t->l=build(ll, m);
138         t->r=build(m+1, rr);
139         t->maintain();
140     }
141     return t;
142 }
143 void update(node * t, int k)
144 {
145     if (t->ll==t->rr) t->lc=t->rc=c[t->ll];
146     else
147     {
148         int m=(t->ll+t->rr)>>1;
149         if (k<=m) update(t->l, k);
150         else update(t->r, k);
151         t->maintain();
152     }
153 }
154 int query(node * t, int ql, int qr)
155 {
156     int ret=0;
157     if (t->ll==ql && t->rr==qr) ret=t->len;
158     else
159     {
160         int m=(t->ll+t->rr)>>1;
161         if (qr<=m) ret=query(t->l, ql, qr);
162         else if (ql>m) ret=query(t->r, ql, qr);
163         else
164         {
165             ret=query(t->r, m+1, qr);
166             if (ret==qr-m && t->r->lc==t->l->rc) ret+=query(t->l, ql, m);
167         }
168     }
169     return ret;
170 }
171
172 inline int lowbit(int x)
173 {
174     return x & -x;
175 }
176 inline void update(int * c, int l, int r, int v)
177 {
178     for (   ;l<=n;l+=lowbit(l)) c[l]+=v;
179     for (r++;r<=n;r+=lowbit(r)) c[r]-=v;
180 }
181 inline int query(int * c, int i)
182 {
183     int ret=0;
184     for ( ;i;i-=lowbit(i)) ret+=c[i];
185     return ret;
186 }
187
188 inline edge * newedge(int point, edge * next)
189 {
190     edge * ret=port_edge++;
191     ret->point=point; ret->next=next;
192     return ret;
193 }
194 inline void link(int u, int v)
195 {
196     e[u]=newedge(v, e[u]); e[v]=newedge(u, e[v]);
197 }
198 inline int lg(int u)
199 {
200     return !u?0:31-__builtin_clz(u);
201 }
202 void dfs_tree(int u)
203 {
204     s[u]=1;
205     for (int i=1;i<=lg(d[u]);i++) p[i][u]=p[i-1][p[i-1][u]];
206     for (edge * i=e[u];i;i=i->next) if (d[i->point]==-1)
207     {
208         f[i->point]=u; d[i->point]=d[u]+1;
209         dfs_tree(i->point);
210         s[u]+=s[i->point];
211         if (s[i->point]>s[son[u]])
212             son[u]=i->point;
213     }
214 }
215 void dfs_chain(int u, int top_u)
216 {
217     idx[u]=++num; top[u]=u;
218     if (son[u]) dfs_chain(son[u], top_u);
219     for (edge * i=e[u];i;i=i->next) if (!idx[i->point])
220         dfs_chain(i->point, i->point);
221 }
222 inline int anc(int u, int k)
223 {
224     for (int i=19;i>=0;i--)
225         if ((k>>i)&1)
226             u=p[k][u];
227     return u;
228 }
229 inline void update(bool c, int u, int v, int s)
230 {
231     while (top[u]!=top[v])
232     {
233         update(sum[c], idx[top[u]], idx[u], s);
234         u=f[top[u]];
235     }
236     update(sum[c], idx[v], idx[u], s);
237 }
238 inline int query(int u)
239 {
240     for ( ; ; )
241     {
242         int l=query(t, idx[top[u]], idx[u]);
243
244         if (l==d[top[u]]-d[u]+1)
245         {
246             if (top[u]==1) return 1;
247             if (c[top[u]]==c[f[top[u]]]) u=f[top[u]];
248             else return top[u];
249         }
250         else
251             return anc(u, l-1);
252     }
253 }

解锁新成就:rank last

时间: 2024-10-08 10:10:34

[BZOJ 3637]Query on a tree VI的相关文章

bzoj 3637: Query on a tree VI 树链剖分 &amp;&amp; AC600

3637: Query on a tree VI Time Limit: 8 Sec  Memory Limit: 1024 MBSubmit: 206  Solved: 38[Submit][Status][Discuss] Description You are given a tree (an acyclic undirected connected graph) with n nodes. The tree nodes are numbered from 1 to n. Each nod

bzoj3637: Query on a tree VI

Description You are given a tree (an acyclic undirected connected graph) with n nodes. The tree nodes are numbered from 1 to n. Each node has a color, white or black. All the nodes are black initially. We will ask you to perfrom some instructions of

BZOJ 3639: Query on a tree VII

Description 一棵树,支持三种操作,修改点权,修改颜色,问所有与他路径上颜色相同的点的最大权,包含这两个点. Sol LCT. 用LCT来维护重边,对于每个节点在建一个set用来维护轻边,这样Link和Cut是时候就非常好操作了,直接Access一下,Splay一下,直接删掉就可以了. 因为set是不统计重边的,然后对于每个节点的信息由他的父亲来保存,因为一个节点可能有很多儿子但一定只有一个父亲. 还有一个问题就是每个点的权值不能建全局的,因为维护的两颗LCT不能够同时删除,所以每个L

bzoj3637 CodeChef SPOJ - QTREE6 Query on a tree VI 题解

题意: 一棵n个节点的树,节点有黑白两种颜色,初始均为白色.两种操作:1.更改一个节点的颜色;2.询问一个节点所处的颜色相同的联通块的大小. 思路: 1.每个节点记录仅考虑其子树时,假设其为黑色时所处的黑色联通块的大小和假设其为白色时所处的白色联通块的大小(树状数组维护). 2.查询时找到深度最小的.与该点颜色相同的且两点之间的点颜色均与这两点相同(两点可以重合)(不妨称它为最远祖先)的答案. 3.修改时应该修改该节点的父亲至最远祖先的父亲上的值. 4.用树链剖分和树状数组维护. 5.寻找最远祖

SPOJ 16549 - QTREE6 - Query on a tree VI 「一种维护树上颜色连通块的操作」

题意 有操作 $0$ $u$:询问有多少个节点 $v$ 满足路径 $u$ 到 $v$ 上所有节点(包括)都拥有相同的颜色$1$ $u$:翻转 $u$ 的颜色 题解 直接用一个 $LCT$ 去暴力删边连边显然会 $T$ 那么只有两个颜色的话就可以建两棵 $LCT$ ,观察到每次单点修改颜色时其子树所包含连通块在原颜色树上与其父亲所代表连通块断开,所以可以看作断开与父节点的边(实际上是点化边的思想),那么其它常规操作即可 注意要建个虚拟节点作为根节点的父亲 注意 $0$ 操作询问的输出,详细解释有在

[hdu 6191] Query on A Tree

Query on A Tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)Total Submission(s): 733    Accepted Submission(s): 275 Problem Description Monkey A lives on a tree, he always plays on this tree. One day, monkey

2017广西邀请赛 Query on A Tree (可持续化字典树)

Query on A Tree 时间限制: 8 Sec  内存限制: 512 MB提交: 15  解决: 3[提交][状态][讨论版] 题目描述 Monkey A lives on a tree. He always plays on this tree.One day, monkey A learned about one of the bit-operations, xor. He was keen of this interesting operation and wanted to pr

spoj 375 Query on a tree (树链剖分)

Query on a tree You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of the i-th edge to ti or Q

【百度之星2014~复赛)解题报告】The Query on the Tree

声明 笔者最近意外的发现 笔者的个人网站http://tiankonguse.com/ 的很多文章被其它网站转载,但是转载时未声明文章来源或参考自 http://tiankonguse.com/ 网站,因此,笔者添加此条声明. 郑重声明:这篇记录<[百度之星2014~复赛)解题报告]The Query on the Tree>转载自 http://tiankonguse.com/ 的这条记录:http://tiankonguse.com/record/record.php?id=673 前言