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 }
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!