P3250 [HNOI2016] 网络 (树剖+堆/整体二分+树上差分+树状数组)
解法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] 网络 (树剖+堆/整体二分+树上差分+树状数组)的更多相关文章
- BZOJ4538 HNOI2016网络(树链剖分+线段树+堆/整体二分+树上差分)
某两个点间的请求只对不在这条路径上的询问有影响.那么容易想到每次修改除该路径上的所有点的答案.对每个点建个两个堆,其中一个用来删除,线段树维护即可.由于一条路径在树剖后的dfs序中是log个区间,所以 ...
- luogu3250 网络 (整体二分+树上差分+树状数组)
首先整体二分,问题变成是否存在经过一个点的满足条件的路径 那么我对于每个路径(a,b,lca),在树状数组的dfn[a]++,dfn[b]++,dfn[lca]--,dfn[fa[lca]--] 然后 ...
- [BZOJ2738]矩阵乘法(整体二分+二维树状数组)
整体二分+二维树状数组. 好题啊!写了一个来小时. 一看这道题,主席树不会搞,只能用离线的做法了. 整体二分真是个好东西,啥都可以搞,尤其是区间第 \(k\) 大这种东西. 我们二分答案,然后用二维树 ...
- 【bzoj2738】矩阵乘法 整体二分+二维树状数组
题目描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入 第一行两个数N,Q,表示矩阵大小和询问组数:接下来N行N列一共N*N个数,表示这个矩阵:再接下来Q行每行5个数 ...
- Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分)
Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分) Description L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之 ...
- P2680 运输计划(二分+树上差分)
P2680 运输计划 链接 分析: 二分+树上差分. 首先可以二分一个答案,那么所有比这个答案大的路径,都需要减去些东西才可以满足这个答案. 那么减去的这条边一定在所有的路径的交集上. 那么如果求快速 ...
- 洛谷 P2680 运输计划-二分+树上差分(边权覆盖)
P2680 运输计划 题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条 ...
- P2680 运输计划 二分+树上差分
又咕咕了几天\(QwQ\) 思路:二分+树上差分 提交:\(\geq5\)次 错因:\(lca\)写错+卡了很久常数(哪位大佬帮我康康,有更好的写法请指出\(QwQ\)) 题解: 我们先将原问题转化为 ...
- 洛谷P3250 [HNOI2016]网络(整体二分+树状数组+树剖)
传送门 据说正解是树剖套堆???然而代码看着稍微有那么一点点长…… 考虑一下整体二分,设当前二分到的答案为$mid$,如果所有大于$mid$的边都经过当前点$x$,那么此时$x$的答案必定小于等于$m ...
随机推荐
- ESP8266 使用 DRV8833驱动板驱动N20电机
RT 手里这块ESP8266是涂鸦的板子,咸鱼上三块一个买了一堆,看ESP8266-12F引脚都差不多的.裸焊了个最小系统,加两个按钮(一个烧录,一个复位) 1. 准备工作 搜索过程中发现 DRV88 ...
- qbxt五一数学Day2
目录 1. 判断素数(素性测试) 1. \(O(\sqrt n)\) 试除 2. Miller-Rabin 素性测试 * 欧拉函数 2. 逆元 3. exgcd(扩展欧几里得) 4. 离散对数(BSG ...
- Frame双向通信插件FrameDataTrans
FrameDataTrans教程 博客园 乳鸽菌 20220729 核心原理是使用postMessage发送数据,window.addEventListener("message" ...
- 原型设计工具Axure RP9下载、汉化操作说明(赠授权码)
Axure是产品经理.交互设计常用的一款原型设计工具,能实现比较复杂的交互效果.其实在功能上是十分齐全的,并且其交互的样式也比较多样,主要是通过动态面板.函数.中继器等几个模块就几乎可以实现任何常见的 ...
- 智慧文旅IOC大数据可视化建设方案
一.建设背景 自2020年以来,疫情对各行各业的都造成了不同程度的影响,对依赖人口消费实现商业价值的文旅行业更是受到了更大的冲击,因此在疫情当下以及科技发达的今天,如何利用科技的手段赋能文旅行业进行数 ...
- Tracer类定义
这个类主要是用于检测光线是否穿过球体.是核心,所有的碰撞都继承于这个类,书上也阐述了很多.详细就看书. 类定义: #pragma once #ifndef __TRACER_HEADER__ #def ...
- Taurus.MVC 微服务框架 入门开发教程:项目集成:5、统一的日志管理。
系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...
- bind搭建内网DNS服务器架构(主从、子域授权、DNS转发器)
实验目的 模拟企业DNS服务架构服务器及原理 实验环境准备 实验架构图 实验设备 DNS服务器4台 主服务器master(centos8):IP_192.168.100.30, 从服务器slave(r ...
- 7个自定义定时任务并发送消息至邮箱或企业微信案例(crontab和at)
前言 更好熟悉掌握at.crontab定时自定义任务用法. 实验at.crontab定时自定义任务运用场景案例. 作业.笔记需要. 定时计划任务相关命令及配置文件简要说明 at 工具 由包 at 提供 ...
- openstack中Glance组件简解
一.Glance组件介绍 1.概念 Glance是OpenStack镜像服务,用来注册.登陆和检索虚拟机镜像.Glance服务提供了一个REST API,使你能够查询虚拟机镜像元数据和检索的实际镜像. ...