传送门

题意:给出一个$N$个点的树,树上每个点有一个位运算符号和一个数值。需要支持以下操作:修改一个点的位运算符号和数值,或者给出两个点$x,y$并给出一个上界$a$,可以选取一个$[0,a]$内的整数值,在从$x$到$y$的路径上,每走到一个点就与这个点对应的数值进行对应的位运算,求到达$y$点时数字的可能的最大值。$N,\text{操作数} \leq 10^5$,数字在$unsigned long long$范围内。


可以先去做NOI2014的起床困难综合征

考虑用起床困难综合征的贪心策略加上树链剖分解决这道题。首先我们需要解决一个问题:在起床困难综合征中,我们每一次枚举一位,就整个跑一边,看当前位取$1$是否会产生更大的贡献;但是在这一道题中显然是不能每一次都跑一边的。我们需要快速地维护每一位为$0$或$1$时这一位运算之后得到的答案。因为每一位之间是不相互冲突的,所以我们可以将$2^{64}-1$和$0$分别带入求解,这样第$i$位为$1$时的贡献就是带入$2^{64}-1$时第$i$位的值,而第$i$位为$0$时的贡献就是带入$0$时第$i$位的值。

接下来我们考虑如何用线段树维护这两个值。可以知道在合并的时候,当前这个区间带入$2^{64}-1$的值时的答案就是左边一半带入$2^{64}-1$时的答案再带到右边得到的答案,$0$同理。所以也可以用位运算很快的表示出来,不是很有思路的可以去看下面的$merge$

然后我们就可以树链剖分然后跳跳跳了。

注意一个细节:因为链可以不是直上直下的,在往上的过程中$dfs$序是在变小的,而在往下的过程中在变大,所以在线段树中需要同时维护从左往右和从右往左计算的值(也就是下面的$ltor$和$rtol$)。

  1. #include<bits/stdc++.h>
  2. #define ull unsigned long long
  3. #define lch (now << 1)
  4. #define rch (now << 1 | 1)
  5. #define mid ((l + r) >> 1)
  6. //This code is written by Itst
  7. using namespace std;
  8.  
  9. inline ull read(){
  10. ull a = ;
  11. char c = getchar();
  12. while(c != EOF && !isdigit(c))
  13. c = getchar();
  14. while(c != EOF && isdigit(c)){
  15. a = (a << ) + (a << ) + (c ^ ');
  16. c = getchar();
  17. }
  18. return a;
  19. }
  20.  
  21. ;
  22. struct node{
  23. ull ltor[] , rtol[] , val;
  24. int op;
  25. node(){
  26. ltor[] = rtol[] = -;
  27. ltor[] = rtol[] = ;
  28. }
  29. }Tree[MAXN << ];
  30. struct Edge{
  31. int end , upEd;
  32. }Ed[MAXN << ];
  33. int head[MAXN] , ind[MAXN] , rk[MAXN] , dep[MAXN] , top[MAXN] , fa[MAXN] , size[MAXN] , son[MAXN] , op[MAXN];
  34. ull num[MAXN];
  35. int ts , N , M , cntEd , K;
  36.  
  37. inline ull calc(ull a , ull b , int op){
  38. switch(op){
  39. :
  40. return a & b;
  41. :
  42. return a | b;
  43. :
  44. return a ^ b;
  45. }
  46. }
  47.  
  48. inline void addEd(int a , int b){
  49. Ed[++cntEd].end = b;
  50. Ed[cntEd].upEd = head[a];
  51. head[a] = cntEd;
  52. }
  53.  
  54. void dfs1(int x , int f){
  55. fa[x] = f;
  56. dep[x] = dep[f] + ;
  57. size[x] = ;
  58. for(int i = head[x] ; i ; i = Ed[i].upEd)
  59. if(Ed[i].end != f){
  60. dfs1(Ed[i].end , x);
  61. size[x] += size[Ed[i].end];
  62. if(size[son[x]] < size[Ed[i].end])
  63. son[x] = Ed[i].end;
  64. }
  65. }
  66.  
  67. void dfs2(int x , int t){
  68. top[x] = t;
  69. ind[x] = ++ts;
  70. rk[ts] = x;
  71. if(!son[x])
  72. return;
  73. dfs2(son[x] , t);
  74. for(int i = head[x] ; i ; i = Ed[i].upEd)
  75. if(Ed[i].end != fa[x] && Ed[i].end != son[x])
  76. dfs2(Ed[i].end , Ed[i].end);
  77. }
  78.  
  79. inline node merge(node l , node r){
  80. node t;
  81. t.ltor[] = (l.ltor[] & r.ltor[]) | (~l.ltor[] & r.ltor[]);
  82. t.ltor[] = (l.ltor[] & r.ltor[]) | (~l.ltor[] & r.ltor[]);
  83. t.rtol[] = (r.rtol[] & l.rtol[]) | (~r.rtol[] & l.rtol[]);
  84. t.rtol[] = (r.rtol[] & l.rtol[]) | (~r.rtol[] & l.rtol[]);
  85. return t;
  86. }
  87.  
  88. void init(int now , int l , int r){
  89. if(l == r){
  90. Tree[now].op = op[rk[l]];
  91. Tree[now].val = num[rk[l]];
  92. Tree[now].ltor[] = Tree[now].rtol[] = calc(- , Tree[now].val , Tree[now].op);
  93. Tree[now].ltor[] = Tree[now].rtol[] = calc( , Tree[now].val , Tree[now].op);
  94. }
  95. else{
  96. init(lch , l , mid);
  97. init(rch , mid + , r);
  98. Tree[now] = merge(Tree[lch] , Tree[rch]);
  99. }
  100. }
  101.  
  102. void modify(int now , int l , int r , int tar){
  103. if(l == r){
  104. Tree[now].op = op[rk[l]];
  105. Tree[now].val = num[rk[l]];
  106. Tree[now].ltor[] = Tree[now].rtol[] = calc(- , Tree[now].val , Tree[now].op);
  107. Tree[now].ltor[] = Tree[now].rtol[] = calc( , Tree[now].val , Tree[now].op);
  108. }
  109. else{
  110. if(mid >= tar)
  111. modify(lch , l , mid , tar);
  112. else
  113. modify(rch , mid + , r , tar);
  114. Tree[now] = merge(Tree[lch] , Tree[rch]);
  115. }
  116. }
  117.  
  118. node query(int now , int l , int r , int L , int R){
  119. if(l >= L && r <= R)
  120. return Tree[now];
  121. node p;
  122. if(mid >= L)
  123. p = merge(p , query(lch , l , mid , L , R));
  124. if(mid < R)
  125. p = merge(p , query(rch , mid + , r , L , R));
  126. return p;
  127. }
  128.  
  129. inline void work(int x , int y , ull maxN){
  130. node l , r;
  131. int tx = top[x] , ty = top[y];
  132. while(tx != ty)
  133. if(dep[tx] > dep[ty]){
  134. l = merge(query( , , N , ind[tx] , ind[x]) , l);
  135. x = fa[tx];
  136. tx = top[x];
  137. }
  138. else{
  139. r = merge(query( , , N , ind[ty] , ind[y]) , r);
  140. y = fa[ty];
  141. ty = top[y];
  142. }
  143. if(dep[x] > dep[y])
  144. l = merge(query( , , N , ind[y] , ind[x]) , l);
  145. else
  146. r = merge(query( , , N , ind[x] , ind[y]) , r);
  147. swap(l.rtol[] , l.ltor[]);
  148. swap(l.rtol[] , l.ltor[]);
  149. l = merge(l , r);
  150. ull ans = , now = ;
  151. ; i >= ; --i){
  152. ull t = (ull) << i , p = l.ltor[] & t , q = l.ltor[] & t;
  153. if(q >= p || now + t > maxN)
  154. ans += q;
  155. else{
  156. now += t;
  157. ans += p;
  158. }
  159. }
  160. printf("%llu\n" , ans);
  161. }
  162.  
  163. int main(){
  164. #ifndef ONLINE_JUDGE
  165. freopen("3613.in" , "r" , stdin);
  166. //freopen("3613.out" , "w" , stdout);
  167. #endif
  168. N = read();
  169. M = read();
  170. K = read();
  171. ; i <= N ; ++i){
  172. op[i] = read();
  173. num[i] = read();
  174. }
  175. ; i < N ; ++i){
  176. int a = read() , b = read();
  177. addEd(a , b);
  178. addEd(b , a);
  179. }
  180. dfs1( , );
  181. dfs2( , );
  182. init( , , N);
  183. int o , x , y;
  184. ull z;
  185. while(M--){
  186. o = read();
  187. x = read();
  188. y = read();
  189. z = read();
  190. )
  191. work(x , y , z);
  192. else{
  193. op[x] = y;
  194. num[x] = z;
  195. modify( , , N , ind[x]);
  196. }
  197. }
  198. ;
  199. }

Luogu3613 睡觉困难综合征/BZOJ4811 Ynoi2017 由乃的OJ 树链剖分、贪心的更多相关文章

  1. bzoj4811 [Ynoi2017]由乃的OJ 树链剖分+贪心+二进制

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4811 题解 我现在为什么都写一题,调一天啊,马上真的退役不花一分钱了. 考虑这道题的弱化版 N ...

  2. [BZOJ4811][YNOI2017]由乃的OJ(树链剖分+线段树)

    起床困难综合症那题,只要从高往低贪心,每次暴力跑一边看这一位输入0和1分别得到什么结果即可. 放到序列上且带修改,只要对每位维护一个线段树,每个节点分别记录0和1从左往右和从右往左走完这段区间后变成的 ...

  3. BZOJ4811 [Ynoi2017]由乃的OJ 树链剖分

    原文链接http://www.cnblogs.com/zhouzhendong/p/8085286.html 题目传送门 - BZOJ4811 题意概括 是BZOJ3668长在树上并加上修改和区间询问 ...

  4. bzoj4811 [Ynoi2017]由乃的OJ 树链剖分+位运算

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4811 因为位运算的结果有可合并性,所以可以树链剖分,线段树维护: 细节很多,特别要注意从左往 ...

  5. 【BZOJ4811】[Ynoi2017]由乃的OJ 树链剖分+线段树

    [BZOJ4811][Ynoi2017]由乃的OJ Description 由乃正在做她的OJ.现在她在处理OJ上的用户排名问题.OJ上注册了n个用户,编号为1-",一开始他们按照编号排名. ...

  6. 【bzoj4811】[Ynoi2017]由乃的OJ 树链剖分+线段树区间合并

    题解: 好像和noi那题并没有什么区别 只是加上了修改和变成树上 比较显然我们可以用树链剖分来维护

  7. 【bzoj4811】[Ynoi2017]由乃的OJ 树链剖分/LCT+贪心

    Description 给你一个有n个点的树,每个点的包括一个位运算opt和一个权值x,位运算有&,l,^三种,分别用1,2,3表示. 每次询问包含三个数x,y,z,初始选定一个数v.然后v依 ...

  8. Luogu3613 睡觉困难综合征

    题面描述https://www.luogu.org/problemnew/show/3613 原题NOI2014起床困难综合症https://www.luogu.org/problemnew/show ...

  9. 洛谷3613睡觉困难综合征(LCT维护链信息(前后缀)+贪心)

    这个题目还是很好啊QWQ很有纪念意义 首先,如果在序列上且是单次询问的话,就是一个非常裸的贪心了QWQ这也是NOI当时原题的问题和数据范围 我们考虑上树的话,应该怎么做? 我的想法是,对于每一位建一个 ...

随机推荐

  1. 卸载Myeclipse10.5 报错“an error has occured.See the log file ...Uninstaller\...”

    找到Myeclipse的安装包,双击它,会出现Uninstaller的按钮,单击卸载即可. 另,网上说,windows下cmd命令道myeclipse.exe 目录,然后执行myeclipse.exe ...

  2. ActiveReports公开课开启报名,学习如何解决中国式复杂报表难题

    ActiveReports实战教学 90分钟解决中国式复杂报表六大需求 [开课时间]4月19日 [主讲老师]葡萄城资深报表专家 [培训方式]网络在线公开课 报名地址

  3. SoapUI SoapUI测试WebService协议接口简介

    SoapUI测试WebService协议接口简介 by:授客 QQ:1033553122 1. 创建项目,入口:File -> New SOAP Project,或者右键默认项目Project- ...

  4. 框架模式MVC在安卓中的实践

    我们采用ListView来演示我们的MVC模式,目录结构: 实体类:包含了书的名字和图片信息 public class Book { //书名 private String name; //书的图片 ...

  5. Scala多重继承及AOP

    package traitandclass /** * Created by zhen on 2018/8/23. */ class Human { println("Human" ...

  6. datagridview 行高列宽的自动设置

    1) 设定行高和列宽自动调整 [C#]// 设定包括Header和所有单元格的列宽自动调整 DataGridView1.AutoSizeColumnsMode = DataGridViewAutoSi ...

  7. python第二十九天-----继续学习第三模块——前几天旅行去了

    subprocess模块 import subprocess subprocess.getstatusoutput('dir')#接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结 ...

  8. 1. svg学习笔记-在网页中使用svg

    在网页中使用svg有以下三种方式 1. svg归根结底来说是一种图像格式,虽然有别于jpeg,gif,png等位图图像格式,所以在网页中能嵌入图像的地方都可以嵌入svg,例如将svg文件设置为< ...

  9. January 28th, 2018 Week 05th Sunday

    I wish you all I ever wanted for you, I wish you the best. 我希望你不负我的期望,愿你一切安好. I hope I can live up t ...

  10. January 04th, 2018 Week 01st Thursday

    Just do what works for you, because there will always be someone who think differently. 就做你自己所能做的,因为 ...