解法1:

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

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

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

解法2:

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

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

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

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

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

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

    开心一刻 昨晚跟我妈语音 妈:我年纪有点大了,想抱孩子了 我:妈,我都多大了,你还想抱我? 妈:我想抱小孩,谁乐意抱你呀! 我:刚好小区有人想找月嫂,要不我帮你联系下? 妈:你给我滚 然后她直接把语音 ...

  2. LyScript 获取上一条与下一条指令

    LyScript 插件默认并没有提供上一条与下一条汇编指令的获取功能,当然你可以使用LyScriptTools工具包直接调用内置命令得到,不过这种方式显然在效率上并不理想,我们需要在LyScript插 ...

  3. 关于hive分区,你知道多少呢?

    ​ 文末查看关键字,回复赠书 一.理论基础 1.Hive分区背景 在Hive Select查询中一般会扫描整个表内容,会消耗很多时间做没必要的工作.有时候只需要扫描表中关心的一部分数据,因此建表时引入 ...

  4. Ubuntu14.04或16.04下普通用户的root权限获得

    Ubuntu系统默认不允许使用root登录,因此初始root帐户是不能使用的,需要在普通账户下利用sudo权限修改root密码.然后以root帐户进行相关操作. 具体操作: 1.打开系统,用普通帐户登 ...

  5. Python 爬取汽车之家口碑数据

    本文仅供学习交流使用,如侵立删!联系方式见文末 汽车之家口碑数据 2021.8.3 更新 增加用户信息参数.认证车辆信息等 2021.3.24 更新 更新最新数据接口 2020.12.25 更新 添加 ...

  6. DolphinScheduler 线上 Meetup 视频回放(07.25)

    上周六下午 DolphinScheduler 社区联合 Doris 社区进行了 2020 年首次线上 Meetup,各位讲师都做了非常精彩的分享,也吸引了 1900 多位技术伙伴观看. 其中 Dolp ...

  7. DolphinScheduler - 1.3 系列核心表结构剖析

    Apache DolphinScheduler 是一个分布式去中心化,易扩展的可视化 DAG 工作流任务调度系统.致力于解决数据处理流程中错综复杂的依赖关系,使调度系统在数据处理流程中开箱即用. 近日 ...

  8. Pycharm5个非常有用的技巧

    PyCharm 是一款非常强大的编写 python 代码的工具.掌握一些小技巧能成倍的提升写代码的效率,本篇介绍几个经常使用的小技巧. 一.分屏展示 当你想同时看到多个文件的时候: 右击标签页: 选择 ...

  9. APT 安装 MySQL 提示错误:dpkg: error: dpkg frontend lock is locked by another process

    在安装 MySQL 的时候提示错误: ubuntu@VM-0-6-ubuntu:/opt$ sudo dpkg -i mysql-apt-config_0.8.22-1_all.deb dpkg: e ...

  10. 使用docker简单编译k20pro内核

    简介 本文将介绍一下如何使用docker编译红米k20pro的内核.作者当时尝试构建内核的原因是为了将3年前(好像是吧)购买的k20pro至尊版(已退役,12GB内存,512GB硬盘)制作成一个小的服 ...