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 }
复制代码

 



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   YHXo  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示