【[AHOI2005]航線規劃】
阿新 • • 發佈:2019-01-02
樹剖維護邊雙
首先我們看到在整個過程中圖是保證連通的,於是我們並不需要LCT來維護連通性
而這些詢問詢問的是兩個點之間關鍵路徑的數量,也就是無論怎麼走都必須走的數量,顯然這就是兩點之間的割邊的數量
由於這裡還有一些刪除操作,樹剖並不支援,所以我們先將所有的答案讀進來,刪掉所有的邊
之後我們就\(Tarjan\)把邊雙縮出來,之後建一棵樹就好了
之後我們倒著完成所有操作
對於詢問操作,我們直接詢問兩點之間的距離就行了
對於刪除操作,由於我們提前刪除完了,所以我們現在需要把邊恢復過來,於是我們如果要恢復\((u,v)\)這條邊的話,如果\((u,v)\)在一個邊雙裡,我們們不需要管這個操作,而如果不在那麼樹上\((u,v)\)
超級長的程式碼
#include<iostream> #include<cstring> #include<cstdio> #include<set> #define re register #define maxn 30005 struct node { int v,nxt; }e[maxn<<3]; int head[maxn],to[maxn],top[maxn],fa[maxn],deep[maxn],sum[maxn],son[maxn]; int a[maxn],b[maxn],belong[maxn]; int opt[maxn<<1],xx[maxn<<1],yy[maxn<<1]; int l[maxn<<2],r[maxn<<2],d[maxn<<2],tag[2][maxn<<2],t[maxn<<2]; int n,m,k,Q,p,num=0; int tot,now; inline int read() { char c=getchar(); int x=0,r=1; while(c<'0'||c>'9'){if(c=='-') r=-1;c=getchar();} while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar(); return x*r; } inline void add_edge(int x,int y) { e[++num].v=y; e[num].nxt=head[x]; head[x]=num; } void dfs1(int r) { sum[r]=1; int maxx=-1; for(re int i=head[r];i;i=e[i].nxt) if(!deep[e[i].v]) { deep[e[i].v]=deep[r]+1; fa[e[i].v]=r; dfs1(e[i].v); sum[r]+=sum[e[i].v]; if(sum[e[i].v]>maxx) maxx=sum[e[i].v],son[r]=e[i].v; } } void dfs2(int r,int topf) { top[r]=topf; to[r]=++k; b[k]=r; if(!son[r]) return; dfs2(son[r],topf); for(re int i=head[r];i;i=e[i].nxt) if(deep[e[i].v]>deep[r]&&son[r]!=e[i].v) dfs2(e[i].v,e[i].v); } void build(int x,int y,int i) { l[i]=x; r[i]=y; tag[0][i]=tag[1][i]=-1; if(x==y) { t[i]=b[x]; d[i]=1; return; } int mid=x+y>>1; build(x,mid,i<<1); build(mid+1,y,i<<1|1); d[i]=d[i<<1]+d[i<<1|1]; } inline void pushdown(int i) { if(tag[0][i]!=-1&&tag[1][i]!=-1) { tag[0][i<<1]=0; tag[0][i<<1|1]=0; d[i<<1]=0; d[i<<1|1]=0; t[i<<1]=tag[1][i<<1]=tag[1][i]; t[i<<1|1]=tag[1][i<<1|1]=tag[1][i]; tag[0][i]=-1; tag[1][i]=-1; } } void change(int x,int y,int v1,int v2,int i) { if(x<=l[i]&&y>=r[i]) { d[i]=v1; t[i]=v2; tag[0][i]=v1; tag[1][i]=v2; return; } pushdown(i); int mid=l[i]+r[i]>>1; if(y<=mid) change(x,y,v1,v2,i<<1); else if(x>mid) change(x,y,v1,v2,i<<1|1); else change(x,y,v1,v2,i<<1),change(x,y,v1,v2,i<<1|1); d[i]=d[i<<1]+d[i<<1|1]; } int query(int x,int y,int i) { if(x<=l[i]&&y>=r[i]) return d[i]; pushdown(i); int mid=l[i]+r[i]>>1; if(y<=mid) return query(x,y,i<<1); if(x>mid) return query(x,y,i<<1|1); return query(x,y,i<<1|1)+query(x,y,i<<1); } int ask(int x,int i) { if(l[i]==r[i]) return t[i]; pushdown(i); int mid=l[i]+r[i]>>1; if(x<=mid) return ask(x,i<<1); return ask(x,i<<1|1); } inline int tree_query(int x,int y) { int ans=0; while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) std::swap(x,y); ans+=query(to[top[x]],to[x],1); x=fa[top[x]]; } if(x==y) return ans; if(deep[x]>deep[y]) std::swap(x,y); ans+=query(to[x]+1,to[y],1); return ans; } inline void tree_change(int x,int y,int k) { while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) std::swap(x,y); change(to[top[x]],to[x],0,k,1); x=fa[top[x]]; } if(x==y) return; if(deep[x]>deep[y]) std::swap(x,y); change(to[x]+1,to[y],0,k,1); } namespace Tarjan { int dfn[maxn],low[maxn],st[maxn]; std::set< std::pair<int,int> > s; int head[maxn]; struct EDGE { int v,nxt; }e[maxn<<3],E[maxn<<3]; int num=0,cnt,mid,top; inline void add(int x,int y) { e[++num].v=y; e[num].nxt=head[x]; head[x]=num; } void tarjan(int x,int fa) { st[++top]=x; dfn[x]=low[x]=++cnt; for(re int i=head[x];i;i=e[i].nxt) if(!dfn[e[i].v]) tarjan(e[i].v,x),low[x]=std::min(low[x],low[e[i].v]); else if(e[i].v!=fa) low[x]=std::min(low[x],dfn[e[i].v]); if(low[x]==dfn[x]) { p++; do { mid=st[top--]; belong[mid]=p; }while(x!=mid); } } void prepare() { n=read(); m=read(); for(re int i=1;i<=m;i++) E[i].v=read(),E[i].nxt=read(); int x,y; while(1) { opt[Q+1]=read(); if(opt[Q+1]==-1) break; if(opt[Q+1]==1) tot++; Q++; xx[Q]=read(); yy[Q]=read(); if(!opt[Q]) { s.insert(std::make_pair(xx[Q],yy[Q])); s.insert(std::make_pair(yy[Q],xx[Q])); } } for(re int i=1;i<=m;i++) if(s.find(std::make_pair(E[i].v,E[i].nxt))==s.end()&&s.find(std::make_pair(E[i].nxt,E[i].v))==s.end()) add(E[i].v,E[i].nxt),add(E[i].nxt,E[i].v); tarjan(1,0); for(re int i=1;i<=n;i++) for(re int j=head[i];j;j=e[j].nxt) if(belong[i]!=belong[e[j].v]) add_edge(belong[i],belong[e[j].v]); } } int main() { Tarjan::prepare(); deep[1]=1; dfs1(1); now=tot; dfs2(1,1); build(1,p,1); change(1,1,0,b[1],1); for(re int T=Q;T;T--) { if(opt[T]==1) a[now--]=tree_query(belong[xx[T]],belong[yy[T]]); else { if(ask(to[belong[xx[T]]],1)==ask(to[belong[yy[T]]],1)) continue; tree_change(belong[xx[T]],belong[yy[T]],++p); } } for(re int i=1;i<=tot;i++) printf("%d\n",a[i]); return 0; }