Luogu-3250 [HNOI2016]網絡
阿新 • • 發佈:2018-12-27
ons std pro stdin ++ rev dep code sta
Luogu-3250 [HNOI2016]網絡
題面
Luogu-3250
題解
CDQ分治...這個應該算是整體二分吧
二分重要度,按照時間從小到大加入大於重要度的邊
對於一個詢問,如果經過這個點的邊數不等於加入的邊數,那就說明有比重要度大而且不經過這個點的邊,然後分成兩部分繼續做
看Candy?大佬的博客學會了一種加邊方法:記錄dfn序,對於一條邊\(u\),\(v\)。讓端點的\(cnt\)++,\(lca\)和\(fa[lca]\)的--,找經過一個點邊數只需要查詢他的子樹大小就好啦
代碼
#include<map> #include<queue> #include<cmath> #include<ctime> #include<stack> #include<bitset> #include<vector> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; inline char gc(){ //static char buf[100000],*p1,*p2; //return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; return getchar(); } inline int read(){ int ans=0,fh=1; char ch=gc(); while(ch<'0'||ch>'9'){if(ch=='-') fh=-1; ch=gc();} while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=gc(); return ans*fh; } const int maxn=2e5+100,maxm=maxn<<1; struct node{ int a,b,v; }c[maxn]; int n,m,head[maxn],nex[maxm],v[maxm],num=1; int tre[maxn],cr[maxn],cl; int fa[maxn],top[maxn],siz[maxn],dep[maxn],son[maxn],dfn[maxn],tim; int tmp1[maxn],tmp2[maxn],p[maxn],ans[maxn],mx,qtot; void revise(int x,int z){ for(int i=x;i<maxn;i+=i&(-i)) if(cr[i]==cl) tre[i]+=z; else cr[i]=cl,tre[i]=z; } int query(int x,int Ans=0){ for(int i=x;i;i-=i&(-i)) if(cr[i]==cl) Ans+=tre[i]; return Ans; } void add(int x,int y){ v[++num]=y; nex[num]=head[x]; head[x]=num; v[++num]=x; nex[num]=head[y]; head[y]=num; } void dfs1(int x,int f,int dp){ fa[x]=f,dep[x]=dp,siz[x]=1; for(int i=head[x];i;i=nex[i]){ int y=v[i]; if(y==f) continue; dfs1(y,x,dp+1); if(siz[y]>siz[son[x]]) son[x]=y; siz[x]+=siz[y]; } } void dfs2(int x,int tp){ top[x]=tp,dfn[x]=++tim; if(son[x]) dfs2(son[x],tp); for(int i=head[x];i;i=nex[i]) if(v[i]!=fa[x]&&v[i]!=son[x]) dfs2(v[i],v[i]); } int Lca(int x,int y){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); x=fa[top[x]]; } return dep[x]<dep[y]?x:y; } void work(int x,int y,int z){ int lca=Lca(x,y); revise(dfn[x],z),revise(dfn[y],z); revise(dfn[lca],-z);if(lca!=1) revise(dfn[fa[lca]],-z); } int check(int x){ int l=dfn[x],r=dfn[x]+siz[x]-1; return query(r)-query(l-1); } void cdq(int l,int r,int L,int R){ if(L>R) return; if(l==r){ int ltot=0;cl++; for(int i=L;i<=R;i++){ int x=p[i],z=c[x].v>0?1:-1; if(~c[x].b) work(c[x].a,c[x].b,z),ltot+=z; else if(check(c[x].a)!=ltot) ans[c[x].v]=l; } return; } int mid=l+r>>1; int lc=0,rc=0,cnt=L-1,ltot=0;cl++; for(int i=L;i<=R;i++){ int x=p[i],z=c[x].v>0?1:-1; if(~c[x].b){ if(abs(c[x].v)>mid) work(c[x].a,c[x].b,z),tmp2[++rc]=x,ltot+=z; else tmp1[++lc]=x; } else{ int pp=check(c[x].a); if(pp!=ltot) tmp2[++rc]=x; else tmp1[++lc]=x; } } for(int i=1;i<=lc;i++) p[++cnt]=tmp1[i]; for(int i=1;i<=rc;i++) p[++cnt]=tmp2[i]; cdq(l,mid,L,L+lc-1),cdq(mid+1,r,L+lc,R); } int main(){ // freopen("3250.in","r",stdin); n=read(),m=read(); int x,y,ms,z; for(int i=1;i<n;i++) x=read(),y=read(),add(x,y); dfs1(1,1,1); dfs2(1,1); for(int i=1;i<=m;i++){ ms=read(),p[i]=i; if(!ms){ x=read(),y=read(),z=read(); c[i]=(node){x,y,z},mx=max(mx,z); } else{ x=read(); if(ms==1) c[i]=c[x],c[i].v*=-1; else c[i].a=x,c[i].b=-1,c[i].v=++qtot; } } memset(ans,-1,sizeof(ans)); cdq(1,mx,1,m); for(int i=1;i<=qtot;i++) printf("%d\n",ans[i]); return 0; }
Luogu-3250 [HNOI2016]網絡