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

传送门

据说正解是树剖套堆???然而代码看着稍微有那么一点点长……

考虑一下整体二分,设当前二分到的答案为$mid$,如果所有大于$mid$的边都经过当前点$x$,那么此时$x$的答案必定小于等于$mid$

然后考虑怎么判断是否所有边都经过某一个点。我们可以用树状数组+树上差分来维护,把每一条边的两个端点的值加1,他们LCA的值减1,LCA父亲的值减1,那么如果这条边经过某一个点,那么这个点子树的和必定为1

于是我们可以把所有大于mid的边都处理出来,然后判断子树的和是否等于路径条数就行了。这个可以用dfs序+树状数组维护

然后整体二分的时候,我们还是能保证时间有序的,如果是修改,那么只有边数大于mid的修改要执行,否则直接扔到左边。询问的话,如果子树和等于大于mid的边数,就扔进左边,否则扔进右边

然后代码里是每一次修改的时候都求一遍LCA的,所以时间复杂度是$O(n log^2n)$,如果用ST表求LCA的话应该能再减掉一个$log$

  1 //minamoto
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  5 char buf[1<<21],*p1=buf,*p2=buf;
  6 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
  7 inline int read(){
  8     #define num ch-'0'
  9     char ch;bool flag=0;int res;
 10     while(!isdigit(ch=getc()))
 11     (ch=='-')&&(flag=true);
 12     for(res=num;isdigit(ch=getc());res=res*10+num);
 13     (flag)&&(res=-res);
 14     #undef num
 15     return res;
 16 }
 17 char sr[1<<21],z[20];int K=-1,Z;
 18 inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
 19 inline void print(int x){
 20     if(K>1<<20)Ot();if(x<0)sr[++K]=45,x=-x;
 21     while(z[++Z]=x%10+48,x/=10);
 22     while(sr[++K]=z[Z],--Z);sr[++K]='
';
 23 }
 24 const int N=2e5+5;
 25 int head[N],Next[N],ver[N],tot;
 26 inline void add_edge(int u,int v){
 27     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
 28 }
 29 struct node{
 30     int op,x,t,ans;
 31     inline bool operator <(const node &b)const
 32     {return t<b.t;}
 33 }q[N],ll[N],rr[N];
 34 int n,m,num,c[N],fa[N],top[N],sz[N],son[N],ls[N],rs[N],dep[N],cnt,mx;
 35 int A[N],B[N],C[N],ans[N];
 36 inline void add(int x,int y){for(;x<=n;x+=x&-x)c[x]+=y;}
 37 inline int query(int x){
 38     int res=0;
 39     for(;x;x-=x&-x) res+=c[x];
 40     return res;
 41 }
 42 inline int query(int l,int r){return query(r)-query(l-1);}
 43 void dfs1(int u){
 44     sz[u]=1,dep[u]=dep[fa[u]]+1,ls[u]=++cnt;
 45     for(int i=head[u];i;i=Next[i]){
 46         int v=ver[i];
 47         if(v!=fa[u]){
 48             fa[v]=u,dfs1(v),sz[u]+=sz[v];
 49             if(sz[son[u]]<sz[v]) son[u]=v;
 50         }
 51     }
 52     rs[u]=cnt;
 53 }
 54 void dfs2(int u,int t){
 55     top[u]=t;
 56     if(son[u]){
 57         dfs2(son[u],t);
 58         for(int i=head[u];i;i=Next[i])
 59         if(ver[i]!=fa[u]&&ver[i]!=son[u])
 60         dfs2(ver[i],ver[i]);
 61     }
 62 }
 63 inline int LCA(int u,int v){
 64     while(top[u]!=top[v])
 65     dep[top[u]]>dep[top[v]]?u=fa[top[u]]:v=fa[top[v]];
 66     return dep[u]<dep[v]?u:v;
 67 }
 68 void update(int u,int v,int x){
 69     int lca=LCA(u,v);
 70     add(ls[u],x),add(ls[v],x),add(ls[lca],-x);
 71     if(fa[lca]) add(ls[fa[lca]],-x);
 72 }
 73 void solve(int l,int r,int ql,int qr){
 74     if(l==r){for(int i=ql;i<=qr;++i) if(q[i].op==2) q[i].ans=l;return;}
 75     int mid=(l+r)>>1,path=0,cl=0,cr=0;
 76     for(int i=ql;i<=qr;++i){
 77         if(q[i].op==2){
 78             if(query(ls[q[i].x],rs[q[i].x])==path) ll[++cl]=q[i];
 79             else rr[++cr]=q[i];
 80         }else{
 81             if(C[q[i].x]<=mid) ll[++cl]=q[i];
 82             else{
 83                 int x=q[i].op?-1:1;path+=x;
 84                 update(A[q[i].x],B[q[i].x],x);
 85                 rr[++cr]=q[i];
 86             }
 87         }
 88     }
 89     for(int i=1;i<=cr;++i) if(rr[i].op!=2){
 90         int x=rr[i].op?1:-1;
 91         update(A[rr[i].x],B[rr[i].x],x);
 92     }
 93     for(int i=1;i<=cl;++i) q[ql+i-1]=ll[i];
 94     for(int i=1;i<=cr;++i) q[ql+cl+i-1]=rr[i];
 95     if(cl) solve(l,mid,ql,ql+cl-1);
 96     if(cr) solve(mid+1,r,ql+cl,qr);
 97 }
 98 int main(){
 99 //    freopen("testdata.in","r",stdin);
100     n=read(),m=read();
101     for(int i=1,u,v;i<n;++i)
102     u=read(),v=read(),add_edge(u,v),add_edge(v,u);
103     dfs1(1),dfs2(1,1);
104     for(int i=1;i<=m;++i){
105         q[i].op=read(),q[i].t=i;
106         if(!q[i].op){
107             A[i]=read(),B[i]=read(),C[i]=read();
108             q[i].x=i,cmax(mx,C[i]);
109         }else q[i].x=read();
110     }
111     solve(-1,mx,1,m);
112     sort(q+1,q+1+m);
113     for(int i=1;i<=m;++i)
114     if(q[i].op==2) print(q[i].ans);
115     Ot();
116     return 0;
117 }
原文地址:https://www.cnblogs.com/bztMinamoto/p/9798479.html