偶然看见了这题,觉得自己 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=;
  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[][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<<], * 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[][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<<], * 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=;i<n;i++)
  50. {
  51. int u=getint(), v=getint();
  52. link(u, v);
  53. }
  54.  
  55. memset(d, 0xFF, sizeof(d)); d[]=;
  56. dfs_tree();
  57. dfs_chain(, );
  58. t=build(, n);
  59. for (int i=;i<=n;i++) update(sum[], idx[i], idx[i], s[i]-);
  60.  
  61. m=getint();
  62. for (int i=;i<=m;i++)
  63. {
  64. int o=getint(), u=getint();
  65.  
  66. if (o==)
  67. {
  68. int f=query(u);
  69. putint(+query(sum[c[f]], idx[f]));
  70. }
  71. else if (u==) c[u]^=;
  72. else
  73. {
  74. int s=query(sum[c[u]], idx[u])+;
  75. c[u]^=;
  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])+;
  83. if (a==) 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==) 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])+;
  92. update(sum[c[u]], idx[f[u]], idx[f[u]], s);
  93. }
  94. }
  95. }
  96.  
  97. return ;
  98. }
  99. inline int getint()
  100. {
  101. register int num=;
  102. register char ch;
  103. do ch=getchar(); while (ch<'' || ch>'');
  104. do num=num*+ch-'', ch=getchar(); while (ch>='' && ch<='');
  105. return num;
  106. }
  107. inline void putint(int num)
  108. {
  109. char stack[];
  110. register int top=;
  111. if (num==) stack[top=]='';
  112. for ( ;num;num/=) stack[++top]=num%+'';
  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+ && 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=;
  134. else
  135. {
  136. int m=(ll+rr)>>;
  137. t->l=build(ll, m);
  138. t->r=build(m+, 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)>>;
  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=;
  157. if (t->ll==ql && t->rr==qr) ret=t->len;
  158. else
  159. {
  160. int m=(t->ll+t->rr)>>;
  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+, 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=;
  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?:-__builtin_clz(u);
  201. }
  202. void dfs_tree(int u)
  203. {
  204. s[u]=;
  205. for (int i=;i<=lg(d[u]);i++) p[i][u]=p[i-][p[i-][u]];
  206. for (edge * i=e[u];i;i=i->next) if (d[i->point]==-)
  207. {
  208. f[i->point]=u; d[i->point]=d[u]+;
  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=;i>=;i--)
  225. if ((k>>i)&)
  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]+)
  245. {
  246. if (top[u]==) return ;
  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-);
  252. }
  253. }

解锁新成就:rank last

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

  1. bzoj 3637: Query on a tree VI 树链剖分 && AC600

    3637: Query on a tree VI Time Limit: 8 Sec  Memory Limit: 1024 MBSubmit: 206  Solved: 38[Submit][Sta ...

  2. BZOJ 3637: Query on a tree VI LCT_维护子树信息_点权转边权_好题

    非常喜欢这道题. 点权转边权,这样每次在切断一个点的所有儿子的时候只断掉一条边即可. Code: #include <cstring> #include <cstdio> #i ...

  3. QTREE6 - Query on a tree VI 解题报告

    QTREE6 - Query on a tree VI 题目描述 给你一棵\(n\)个点的树,编号\(1\)~\(n\).每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我 ...

  4. bzoj3637: Query on a tree VI

    Description You are given a tree (an acyclic undirected connected graph) with n nodes. The tree node ...

  5. BZOJ3637 Query on a tree VI(树链剖分+线段树)

    考虑对于每一个点维护子树内与其连通的点的信息.为了换色需要,记录每个点黑白两种情况下子树内连通块的大小. 查询时,找到深度最浅的同色祖先即可,这可以比较简单的树剖+线段树乱搞一下(似乎就是qtree3 ...

  6. SPOJ QTREE Query on a tree VI

    You are given a tree (an acyclic undirected connected graph) with n nodes. The tree nodes are number ...

  7. BZOJ 3639: Query on a tree VII

    Description 一棵树,支持三种操作,修改点权,修改颜色,问所有与他路径上颜色相同的点的最大权,包含这两个点. Sol LCT. 用LCT来维护重边,对于每个节点在建一个set用来维护轻边,这 ...

  8. QTREE6&&7 - Query on a tree VI &&VII

    树上连通块 不用具体距离,只询问连通块大小或者最大权值 可以类比Qtree5的方法,但是记录东西很多,例如子树有无0/1颜色等 一个trick,两个LCT分离颜色 每个颜色在边上. 仅保留连通块顶部不 ...

  9. 2019.02.17 spoj Query on a tree VI(链分治)

    传送门 题意简述:给你一棵nnn个黑白点的树,支持改一个点的颜色,询问跟某个点颜色相同的连通块大小. 思路: 还是链分治 233 记fi,0/1f_{i,0/1}fi,0/1​表示iii的所有颜色为0 ...

随机推荐

  1. Maven联网问题

    关于Maven联网问题 关于如何找到Maven默认的本地仓库问题 修改Maven默认本地仓库 找到 <localRepository>/path/to/local/repo</loc ...

  2. sqlserverdriver配置方法 jdbc连接sqlserver

    一.下载驱动程序. 下载地址:http://download.microsoft.com/download/8/B/D/8BDABAE2-B6EA-41D4-B903-7916EF3690EF/sql ...

  3. apicloud 解析

    function jiexi(id) { var getTabBarActivityUrl = '/QuestionReport?filter='; var urlParam = {}; ajaxRe ...

  4. ASP.net页面代码执行顺序

    <%=TextBox1 .Text%> <asp:TextBox ID="TextBox1" runat="server">abc< ...

  5. [转载 ]POJ 1273 最大流模板

    转载 百度文库花了5分下的 不过确实是自己需要的东西经典的最大流题POJ1273 ——其他练习题 POJ3436 . 题意描述: 现在有m个池塘(从1到m开始编号,1为源点,m为汇点),及n条水渠,给 ...

  6. DOM事件简介--摘自admin10000

    Click.touch.load.drag.change.input.error.risize — 这些都是冗长的DOM(文档对象模型)事件列表的一部分.事件可以在文档(Document)结构的任何部 ...

  7. React Native工作小技巧及填坑记录

    以下是本人在React Native开发工作中使用的一些小技巧,记录一下. 1.从网络上拉取下来的React Native缺少React和React Native库. 终端 1. cd 项目根目录 2 ...

  8. Golang游戏服务器

    我对和GOLANG写MMO服务器的一些遐想: 1.沙盒(隔离性) SKYNET:原生LUA STATE作为沙盒, 进行服务器间隔离安全性高: 服务可以很容易的配置到不同节点之上. GO:估计用RECO ...

  9. sql语句变量定义和样例

    变量和与常量 1.定义和使用局部变量说明:局部变量是用户可自定义的变量,它的作用范围仅在程序内部.局部变量的名称是用户自定义的,命名的局部变量名要符合SQL Server 2000标识符命名规则,必须 ...

  10. Linux自己安装redis扩展

    注意:目录的权限   chomd 777 -R 注意:下面涉及的目录只是我自己安装的目录,要找自己对应的目录文件 1.安装redis 下载:https://github.com/nicolasff/p ...