洛谷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]='\n'; 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 }
深深地明白自己的弱小