解法1:

本题有插入路径和删除路径,在每个节点维护插入堆和删除堆,查询时两者top一样则一直弹出。如果每个节点维护的是经过他的路径,显然有些不好处理,正难则反,每个点维护不经过他的路径,那么x节点出了故障时,我们就查询x,查询到的就是x出故障后不受影响的路径。

(洛谷上有一个点一直过不了,似乎是之后加强过的数据)。

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 const int N=200010;
  4. 4 int tot,sum,head[N],nxt[N<<1],to[N<<1],id[N],top[N],sze[N],son[N],dep[N],fa[N];
  5. 5 int n,m;
  6. 6
  7. 7 inline void add(int x,int y){
  8. 8 nxt[++tot]=head[x];
  9. 9 head[x]=tot;
  10. 10 to[tot]=y;
  11. 11 }
  12. 12
  13. 13 inline int read()
  14. 14 {
  15. 15 int x=0,flag=1;
  16. 16 char ch=getchar();
  17. 17 while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
  18. 18 while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
  19. 19 return x*flag;
  20. 20 }
  21. 21
  22. 22 struct node{//每个节点存两个堆
  23. 23 priority_queue<int>a,d;
  24. 24 void push(int x){a.push(x);}
  25. 25 void del(int x){d.push(x);}
  26. 26 int top(){
  27. 27 while(!d.empty()&&a.top()==d.top()) a.pop(),d.pop();
  28. 28 if(a.empty()) return -1;
  29. 29 return a.top();
  30. 30 }
  31. 31 }t[N*5];
  32. 32
  33. 33 struct ac{
  34. 34 int x,y,z;
  35. 35 }q[N];
  36. 36
  37. 37 struct AC{
  38. 38 int l,r;
  39. 39 }Data[N];
  40. 40
  41. 41 inline void dfs1(int x,int f){
  42. 42 dep[x]=dep[f]+1,fa[x]=f,sze[x]=1;
  43. 43 for(register int i=head[x];i;i=nxt[i]){
  44. 44 int y=to[i];
  45. 45 if(y==f) continue;
  46. 46 dfs1(y,x);
  47. 47 sze[x]+=sze[y];
  48. 48 if(sze[y]>=sze[son[x]]) son[x]=y;//曾老给的数据要卡这一步
  49. 49 }
  50. 50 }
  51. 51
  52. 52 inline void dfs2(int x,int t){
  53. 53 top[x]=t;
  54. 54 id[x]=++sum;
  55. 55 if(!son[x]) return ;
  56. 56 dfs2(son[x],t);
  57. 57 for(register int i=head[x];i;i=nxt[i]){
  58. 58 int y=to[i];
  59. 59 if(y!=fa[x]&&y!=son[x])
  60. 60 dfs2(y,y);
  61. 61 }
  62. 62 }
  63. 63
  64. 64 bool cmp(AC a,AC b){
  65. 65 return a.l<b.l;
  66. 66 }
  67. 67
  68. 68 inline void modify(int k,int l,int r,int L,int R,int type,int val){
  69. 69 if(L>R) return ;
  70. 70 if(L<=l&&R>=r){
  71. 71 if(!type) t[k].push(val);
  72. 72 else t[k].del(val);
  73. 73 return ;
  74. 74 }
  75. 75 int mid=(l+r)>>1;
  76. 76 if(L<=mid) modify(k<<1,l,mid,L,R,type,val);
  77. 77 if(R>mid) modify(k<<1|1,mid+1,r,L,R,type,val);
  78. 78 }
  79. 79
  80. 80 inline void update(int x,int y,int type,int val){
  81. 81 int cnt=0;
  82. 82 while(top[x]!=top[y]){
  83. 83 if(dep[top[x]]<dep[top[y]]) swap(x,y);
  84. 84 Data[++cnt]=(AC){id[top[x]],id[x]};
  85. 85 x=fa[top[x]];
  86. 86 }
  87. 87 if(dep[x]<dep[y]) swap(x,y);
  88. 88 Data[++cnt]=(AC){id[y],id[x]};
  89. 89 sort(Data+1,Data+cnt+1,cmp);
  90. 90 int last=1;
  91. 91 for(register int i=1;i<=cnt;i++) modify(1,1,n,last,Data[i].l-1,type,val),last=Data[i].r+1;
  92. 92 modify(1,1,n,last,n,type,val);
  93. 93 }
  94. 94
  95. 95 inline int query(int k,int l,int r,int x){
  96. 96 if(l==r&&l==x)
  97. 97 return t[k].top();
  98. 98 int mid=(l+r)>>1;
  99. 99 if(x<=mid) return max(t[k].top(),query(k<<1,l,mid,x));
  100. 100 else return max(t[k].top(),query(k<<1|1,mid+1,r,x));
  101. 101 }
  102. 102
  103. 103 int main(){
  104. 104 int x,y,z,type;
  105. 105 n=read(),m=read();
  106. 106 for(register int i=1;i<n;i++){
  107. 107 x=read(),y=read();
  108. 108 add(x,y);add(y,x);
  109. 109 }
  110. 110 dfs1(1,0);dfs2(1,1);//树链剖分
  111. 111 for(register int i=1;i<=m;i++){
  112. 112 type=read();
  113. 113 if(type==0){
  114. 114 x=read(),y=read(),z=read();
  115. 115 update(x,y,0,z);
  116. 116 q[i]=(ac){x,y,z};//存每条交互链
  117. 117 }
  118. 118 if(type==1){
  119. 119 x=read();
  120. 120 update(q[x].x,q[x].y,1,q[x].z);
  121. 121 }
  122. 122 if(type==2){
  123. 123 x=read();
  124. 124 printf("%d\n",query(1,1,n,id[x]));
  125. 125 }
  126. 126 }
  127. 127 return 0;
  128. 128 }

解法2:

题目可以使用整体二分的前提就是每组询问可以二分解答。

二分答案值mid,对于要查询的节点x,如果>mid的路径都经过x,那么答案一定小等于mid,反之大于mid。

将所有操作放在一起,标上标记以区分操作类型,套用整体二分的模板就可以了。

具体操作:对于针对的值>mid的操作,采用树上差分的思想,用树状数组维护子数和,统计经过x的>mid的路径有多少条。

(树状数组尤其是可以维护经过每个点的路径有多少条的差分)

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 const int N=1e5+10,INF=1e9;
  4. 4 int dep[N],fa[N],sze[N],son[N],top[N],in[N],out[N],total;
  5. 5 int head[N],to[N<<1],nxt[N<<1],tot;
  6. 6 int n,m,c[N],A[N<<1],B[N<<1],C[N<<1];
  7. 7 struct node{
  8. 8 int op,t,x,res;
  9. 9 bool operator<(const node &b) const{return t<b.t;}//保证操作按照时间顺序排列
  10. 10 }q[N*3],ql[N*3],qr[N*3];
  11. 11 void addedge(int u,int v){
  12. 12 nxt[++tot]=head[u];
  13. 13 head[u]=tot;
  14. 14 to[tot]=v;
  15. 15 }
  16. 16
  17. 17 void dfs1(int u,int f){
  18. 18 dep[u]=dep[f]+1,sze[u]=1,fa[u]=f;
  19. 19 in[u]=++total;
  20. 20 for(int i=head[u];i;i=nxt[i]){
  21. 21 int v=to[i];
  22. 22 if(v!=f){
  23. 23 dfs1(v,u);
  24. 24 sze[u]+=sze[v];
  25. 25 if(sze[v]>sze[son[u]]) son[u]=v;
  26. 26 }
  27. 27 }
  28. 28 out[u]=total;
  29. 29 }
  30. 30
  31. 31 void dfs2(int u,int t){
  32. 32 top[u]=t;
  33. 33 if(son[u]) dfs2(son[u],t);
  34. 34 for(int i=head[u];i;i=nxt[i]){
  35. 35 int v=to[i];
  36. 36 if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
  37. 37 }
  38. 38 }
  39. 39
  40. 40 int lca(int u,int v){
  41. 41 while(top[u]!=top[v]){
  42. 42 if(dep[top[u]]<dep[top[v]]) swap(u,v);
  43. 43 u=fa[top[u]];
  44. 44 }
  45. 45 return dep[u]<dep[v]?u:v;
  46. 46 }
  47. 47
  48. 48 void add(int x,int y){
  49. 49 for(;x<=n;x+=x&(-x)) c[x]+=y;
  50. 50 }
  51. 51
  52. 52 int ask(int x){
  53. 53 int res=0;
  54. 54 for(;x;x-=x&(-x)) res+=c[x];
  55. 55 return res;
  56. 56 }
  57. 57
  58. 58 void modify(int x,int y,int v){//树上差分
  59. 59 int z=lca(x,y);
  60. 60 add(in[x],v),add(in[y],v),add(in[z],-v);
  61. 61 if(fa[z]) add(in[fa[z]],-v);
  62. 62 }
  63. 63
  64. 64 void solve(int lval,int rval,int st,int ed){
  65. 65 if(st>ed) return ;
  66. 66 if(lval==rval){
  67. 67 for(int i=st;i<=ed;i++)
  68. 68 if(q[i].op==2) q[i].res=lval;//记录答案
  69. 69 return ;
  70. 70 }
  71. 71 int mid=(lval+rval)>>1,cnt=0,lt=0,rt=0;
  72. 72 for(int i=st;i<=ed;i++){
  73. 73 if(q[i].op==2){
  74. 74 int k=ask(out[q[i].x])-ask(in[q[i].x]-1);
  75. 75 if(k==cnt) ql[++lt]=q[i];
  76. 76 else qr[++rt]=q[i];
  77. 77 }
  78. 78 else{
  79. 79 if(C[q[i].x]<=mid) ql[++lt]=q[i];
  80. 80 else{
  81. 81 int v=q[i].op?-1:1;
  82. 82 cnt+=v;
  83. 83 modify(A[q[i].x],B[q[i].x],v);
  84. 84 qr[++rt]=q[i];
  85. 85 }
  86. 86 }
  87. 87 }
  88. 88 for(int i=1;i<=rt;i++){//还原
  89. 89 if(qr[i].op!=2){
  90. 90 int v=qr[i].op?1:-1;
  91. 91 modify(A[qr[i].x],B[qr[i].x],v);
  92. 92 }
  93. 93 }
  94. 94 for(int i=1;i<=lt;i++) q[st+i-1]=ql[i];
  95. 95 for(int i=1;i<=rt;i++) q[st+lt+i-1]=qr[i];
  96. 96 if(lt) solve(lval,mid,st,st+lt-1);
  97. 97 if(rt) solve(mid+1,rval,st+lt,ed);
  98. 98 }
  99. 99
  100. 100 int main(){
  101. 101 scanf("%d%d",&n,&m);
  102. 102 for(int i=1;i<n;i++){
  103. 103 int u,v;
  104. 104 scanf("%d%d",&u,&v);
  105. 105 addedge(u,v);addedge(v,u);
  106. 106 }
  107. 107 dfs1(1,0);dfs2(1,1);
  108. 108 for(int i=1;i<=m;i++){
  109. 109 scanf("%d",&q[i].op);
  110. 110 q[i].t=i;//记录操作编号
  111. 111 if(!q[i].op){
  112. 112 scanf("%d%d%d",&A[i],&B[i],&C[i]);
  113. 113 q[i].x=i;//记录操作1的编号
  114. 114 }
  115. 115 else scanf("%d",&q[i].x);
  116. 116 }
  117. 117 solve(-1,INF,1,m);//值域从-1和INF分,那些无解的就是-1
  118. 118 sort(q+1,q+m+1);
  119. 119 for(int i=1;i<=m;i++){
  120. 120 if(q[i].op==2) printf("%d\n",q[i].res);
  121. 121 }
  122. 122 return 0;
  123. 123 }

P3250 [HNOI2016] 网络 (树剖+堆/整体二分+树上差分+树状数组)的更多相关文章

  1. BZOJ4538 HNOI2016网络(树链剖分+线段树+堆/整体二分+树上差分)

    某两个点间的请求只对不在这条路径上的询问有影响.那么容易想到每次修改除该路径上的所有点的答案.对每个点建个两个堆,其中一个用来删除,线段树维护即可.由于一条路径在树剖后的dfs序中是log个区间,所以 ...

  2. luogu3250 网络 (整体二分+树上差分+树状数组)

    首先整体二分,问题变成是否存在经过一个点的满足条件的路径 那么我对于每个路径(a,b,lca),在树状数组的dfn[a]++,dfn[b]++,dfn[lca]--,dfn[fa[lca]--] 然后 ...

  3. [BZOJ2738]矩阵乘法(整体二分+二维树状数组)

    整体二分+二维树状数组. 好题啊!写了一个来小时. 一看这道题,主席树不会搞,只能用离线的做法了. 整体二分真是个好东西,啥都可以搞,尤其是区间第 \(k\) 大这种东西. 我们二分答案,然后用二维树 ...

  4. 【bzoj2738】矩阵乘法 整体二分+二维树状数组

    题目描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入 第一行两个数N,Q,表示矩阵大小和询问组数:接下来N行N列一共N*N个数,表示这个矩阵:再接下来Q行每行5个数 ...

  5. Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分)

    Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分) Description L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之 ...

  6. P2680 运输计划(二分+树上差分)

    P2680 运输计划 链接 分析: 二分+树上差分. 首先可以二分一个答案,那么所有比这个答案大的路径,都需要减去些东西才可以满足这个答案. 那么减去的这条边一定在所有的路径的交集上. 那么如果求快速 ...

  7. 洛谷 P2680 运输计划-二分+树上差分(边权覆盖)

    P2680 运输计划 题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条 ...

  8. P2680 运输计划 二分+树上差分

    又咕咕了几天\(QwQ\) 思路:二分+树上差分 提交:\(\geq5\)次 错因:\(lca\)写错+卡了很久常数(哪位大佬帮我康康,有更好的写法请指出\(QwQ\)) 题解: 我们先将原问题转化为 ...

  9. 洛谷P3250 [HNOI2016]网络(整体二分+树状数组+树剖)

    传送门 据说正解是树剖套堆???然而代码看着稍微有那么一点点长…… 考虑一下整体二分,设当前二分到的答案为$mid$,如果所有大于$mid$的边都经过当前点$x$,那么此时$x$的答案必定小于等于$m ...

随机推荐

  1. 第十五天python3 文件IO(一)

    一.文件打开 open(path,flag[,encoding][,errors]) 参数说明: path:要打开文件的路径 flag:打开方式( r:以只读的方式打开文件,文件的描述符放在文件开头 ...

  2. DTS搭载全新自研内核,突破两地三中心架构的关键技术|腾讯云数据库

    随着企业规模的扩大,对数据库可用性要求越来越高,更多企业采用两地三中心.异地多活的架构,以提高数据库的异常事件应对能力. 在数据库领域,我们常听的"两地三中心"."异地多 ...

  3. mysql show操作

    SHOW CHARACTER SET 显示所有可用的字符集 SHOW CHARACTER SET; SHOW CHARACTER SET LIKE 'latin%'; SHOW COLLATION 输 ...

  4. day15--Java常用类之日期相关类

    Java常用类 3.日期相关类 3.1Date类 在标准Java类库中包含一个Date类,它的对象表示一个特定的瞬间,精确到毫秒.在网上商城下单时,在对报销单进行审核时,都需要获取当前的时间,通过Da ...

  5. JVM内存模型和结构详解(五大模型图解)

    JVM内存模型和Java内存模型都是面试的热点问题,名字看感觉都差不多,实际上他们之间差别还是挺大的. 通俗点说,JVM内存结构是与JVM的内部存储结构相关,而Java内存模型是与多线程编程相关@mi ...

  6. 我和Apache DolphinScheduler的这一年

    Apache DolphinScheduler,为Apache开源项目, 简称"DS", 中文名 "小海豚调度"(海豚聪明.人性化,又左右脑可互相换班,终生不用 ...

  7. 在使用amoeba连接数据库时,报错java.lang.Exception: poolName=slaves, no valid pools

    项目场景:Mysql 实现数据库读写分离 搭建3台MySQL服务器,完成主从复制,搭建一台amoeba服务器,完成MySQL的读写分离 问题描述: 问题1. 在服务搭建完毕后,利用客户机连接amoeb ...

  8. java学习第五天异常机制.day14

    异常处理机制 确保程序的正常执行.这种机制称为异常处理机制 异常对象 常用方法 方法介绍 toString 返回异常类型和异常信息 getMessage 返回异常信息 printStackTrace ...

  9. Web 前端实战:JQ 实现树形控件

    前言 这是一篇个人练习 Web 前端各种常见的控件.组件的实战系列文章.本篇文章将介绍个人通过 JQuery + 无序列表 + CSS 动画完成一个简易的树形控件. 最终实现的效果是: 这样结构比较复 ...

  10. transform: scale() 实现鼠标悬浮在元素之上出现和消失

    前言 transform属性允许你旋转,缩放,倾斜或平移给定元素.其中scale(x, y)就是实现元素缩放的属性值. scale(x, y)的 x 乘以原本元素的 x:y 乘以原本的元素 y,就可以 ...