【算法】树链剖分+线段树

【题解】

树链剖分算法:http://www.cnblogs.com/onioncyc/p/6207462.html

定义线段树结构体有l,r,lc,rc,sum,data。

lc表示左端颜色,rc表示右端颜色,sum表示颜色种类,data表示区间置为同一个数的标记。

修改的时候要上推和下传,查询的时候要下传。

我的写法是打lazy标记的时候顺便把子树的其它参数都修改完毕,方便直接调用。

访问到有lazy标记的子树时把标记下传给左右子树并修改左右子树的其他参数。

左右端颜色相同的处理方法见:http://blog.csdn.net/u011645923/article/details/43087133

还是注意树链剖分后操作要使用新编号pos[i]。

  1. #include<cstdio>
  2. #include<cctype>
  3. #include<algorithm>
  4. using namespace std;
  5. int read()
  6. {
  7. char c;int s=,t=;
  8. while(!isdigit(c=getchar()))if(c=='-')t=-;
  9. do{s=s*+c-'';}while(isdigit(c=getchar()));
  10. return s*t;
  11. }
  12. const int maxn=;
  13. int first[maxn],size[maxn],deep[maxn],f[maxn],top[maxn],pos[maxn],LC,RC,n,m,tot,dfsnum,a[maxn];
  14. struct edge{int u,v,from;}e[maxn*];
  15. struct tree{int lc,rc,sum,l,r,data;}t[maxn*];
  16. void insert(int u,int v)
  17. {tot++;e[tot].u=u;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
  18. void dfs1(int x,int fa)
  19. {
  20. size[x]=;
  21. for(int i=first[x];i;i=e[i].from)
  22. if(e[i].v!=fa)
  23. {
  24. int y=e[i].v;
  25. f[y]=x;
  26. deep[y]=deep[x]+;
  27. dfs1(y,x);
  28. size[x]+=size[y];
  29. }
  30. }
  31. void dfs2(int x,int tp,int fa)
  32. {
  33. int k=;
  34. pos[x]=++dfsnum;
  35. top[x]=tp;
  36. for(int i=first[x];i;i=e[i].from)
  37. if(e[i].v!=fa&&size[e[i].v]>size[k])k=e[i].v;
  38. if(k==)return;
  39. dfs2(k,tp,x);
  40. for(int i=first[x];i;i=e[i].from)
  41. if(e[i].v!=fa&&e[i].v!=k)dfs2(e[i].v,e[i].v,x);
  42. }
  43. void build(int k,int l,int r)
  44. {
  45. t[k].l=l;t[k].r=r;
  46. if(l==r){t[k].lc=;t[k].rc=;t[k].sum=;t[k].data=;return;}
  47. else
  48. {
  49. int mid=(l+r)>>;
  50. build(k<<,l,mid);
  51. build(k<<|,mid+,r);
  52. }
  53. }
  54. void pushdown(int k)
  55. {
  56. if(t[k].data)
  57. {
  58. t[k<<].sum=t[k<<|].sum=;
  59. t[k<<].data=t[k<<|].data=t[k].data;
  60. t[k<<].lc=t[k<<].rc=t[k].data;
  61. t[k<<|].lc=t[k<<|].rc=t[k].data;
  62. }
  63. t[k].data=;
  64. }
  65. void pushup(int k)
  66. {
  67. t[k].lc=t[k<<].lc;
  68. t[k].rc=t[k<<|].rc;
  69. t[k].sum=t[k<<].sum+t[k<<|].sum;
  70. if(t[k<<].rc==t[k<<|].lc)t[k].sum--;
  71. }
  72. void change(int k,int l,int r,int x)//区间修改需要上推&&下传
  73. {
  74. pushdown(k);
  75. int left=t[k].l,right=t[k].r;
  76. if(l<=left&&right<=r){t[k].data=x;t[k].sum=;t[k].lc=t[k].rc=x;}
  77. else
  78. {
  79. int mid=(left+right)>>;
  80. if(l<=mid)change(k<<,l,r,x);
  81. if(r>mid)change(k<<|,l,r,x);
  82. pushup(k);
  83. }
  84. }
  85. int ask(int k,int l,int r)//区间查询只需要下传
  86. {
  87. pushdown(k);
  88. int left=t[k].l,right=t[k].r;
  89. if(l==left)LC=t[k].lc;
  90. if(r==right)RC=t[k].rc;
  91. if(l<=left&&right<=r){return t[k].sum;}
  92. else
  93. {
  94. int mid=(left+right)>>,sums=,ok=;
  95. if(l<=mid)sums=ask(k<<,l,r),ok++;
  96. if(r>mid)sums+=ask(k<<|,l,r),ok++;
  97. if(ok==&&t[k<<].rc==t[k<<|].lc)sums--;//只取一边的话就不需要判断了
  98. return sums;
  99. }
  100. }
  101. void update(int x,int y,int z)
  102. {
  103. while(top[x]!=top[y])
  104. {
  105. if(deep[top[x]]<deep[top[y]])swap(x,y);
  106. change(,pos[top[x]],pos[x],z);//!!!
  107. x=f[top[x]];
  108. }
  109. if(pos[x]>pos[y])swap(x,y);
  110. change(,pos[x],pos[y],z);
  111. }
  112. int solve(int x,int y)
  113. {
  114. int sums=,ansx=,ansy=;//分别表示x和y的左端点颜色
  115. while(top[x]!=top[y])
  116. {
  117. if(deep[top[x]]<deep[top[y]])swap(x,y),swap(ansx,ansy);
  118. sums+=ask(,pos[top[x]],pos[x]);
  119. if(RC==ansx)sums--;
  120. ansx=LC;
  121. x=f[top[x]];
  122. }
  123. if(pos[x]>pos[y])swap(x,y),swap(ansx,ansy);
  124. sums+=ask(,pos[x],pos[y]);
  125. if(ansx==LC)sums--;
  126. if(ansy==RC)sums--;
  127. return sums;
  128. }
  129. int main()
  130. {
  131. n=read();m=read();
  132. for(int i=;i<=n;i++)a[i]=read();
  133. for(int i=;i<n;i++)
  134. {
  135. int u=read(),v=read();
  136. insert(u,v);
  137. insert(v,u);
  138. }
  139. dfs1(,-);dfs2(,,-);
  140. build(,,n);
  141. for(int i=;i<=n;i++)update(i,i,a[i]+);//颜色+1避免0的问题
  142. for(int i=;i<=m;i++)
  143. {
  144. char c=getchar();
  145. while(!(c=='C'||c=='Q'))c=getchar();
  146. if(c=='C')
  147. {
  148. int x=read(),y=read(),z=read();
  149. update(x,y,z+);
  150. }
  151. else
  152. {
  153. int x=read(),y=read();
  154. printf("%d\n",solve(x,y));
  155. }
  156. }
  157. return ;
  158. }

【BZOJ】2243 [SDOI2011]染色的更多相关文章

  1. BZOJ 2243: [SDOI2011]染色 [树链剖分]

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6651  Solved: 2432[Submit][Status ...

  2. bzoj 2243 [SDOI2011]染色(树链剖分,线段树)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4637  Solved: 1726[Submit][Status ...

  3. Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5020  Solved: 1872[Submit][Status ...

  4. bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 7925  Solved: 2975[Submit][Status ...

  5. bzoj 2243: [SDOI2011]染色 (树链剖分+线段树 区间合并)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9854  Solved: 3725[Submit][Status ...

  6. BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  7. BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并

    2243: [SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数 ...

  8. bzoj 2243 [SDOI2011]染色(树链剖分+线段树合并)

    [bzoj2243][SDOI2011]染色 2017年10月20日 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询 ...

  9. 洛谷 P2486 [SDOI2011]染色/bzoj 2243: [SDOI2011]染色 解题报告

    [SDOI2011]染色 题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同 ...

  10. BZOJ 2243 [SDOI2011]染色 (树链剖分)(线段树区间修改)

    [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6870  Solved: 2546[Submit][Status][Disc ...

随机推荐

  1. C++ Primer Plus学习:第六章

    C++入门第六章:分支语句和逻辑运算符 if语句 语法: if (test-condition) statement if else语句 if (test-condition) statement1 ...

  2. 第八次java笔记

  3. 微信获取 openid 静默及非静默

    <?php /* 需要的微信公众号配置信息 APPID : 绑定支付的APPID APPSECRET : 公众帐号secert */ class Index { // 配置账号信息 privat ...

  4. c 用指针操作结构体数组

    重点:指针自加,指向下一个结构体数组单元 #include <stdio.h> #include <stdlib.h> #include <string.h> #d ...

  5. CDN加速-内容分发网络

    内容分发网络 (互联网技术) 编辑 CDN的全称是Content Delivery Network,即内容分发网络.其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输 ...

  6. BZOJ5011 JXOI2017颜色(主席树)

    相当于求满足在子段中出现的颜色只在该子段中出现的非空子段数量.这也就相当于其中出现的颜色最左出现的位置在左端点右侧,最右出现的位置在右端点左侧.那么若固定某个端点,仅考虑对该端点的限制,会有一段合法区 ...

  7. 《Unix网络编程卷1:套接字联网API》读书笔记

    第一部分:简介和TCP/IP 第1章:简介 第2章:传输层:TCP.UDP和SCTP TCP:传输控制协议,复杂.可靠.面向连接协议 UDP:用户数据报协议,简单.不可靠.无连接协议 SCTP:流控制 ...

  8. TCP的拥塞控制 (二)

    TCP Reno TCP  Reno引入了ssthresh(Slow Start threshold)变量,作为TCP的Slow Start和Congestion Avoidance两个阶段的分界线. ...

  9. 【DP】【P5080】 Tweetuzki 爱序列

    Description Tweetuzki 有一个长度为 \(n\) 的序列 \(a_1~,~a_2~,~\dots~,a_n\). 他希望找出一个最大的 \(k\),满足在原序列中存在一些数 \(b ...

  10. 【数学】【背包】【NOIP2018】P5020 货币系统

    传送门 Description 在网友的国度中共有 \(n\) 种不同面额的货币,第 \(i\) 种货币的面额为 \(a[i]\),你可以假设每一种货币都有无穷多张.为了方便,我们把货币种数为 \(n ...