hdu 6200 mustedge mustedge mustedge(dfs序+树状数组+并查集)
题目链接:hdu 6200 mustedge mustedge mustedge
题意:
一开始给你一个有n个节点m条无向边的图,现在定义mustedge为u->v的路径上必须经过的边。
现在有q个操作:
1 x y x->y加条无向边
2 x y 查询x->y上有多少条mustedge。
题解:
贴一下叉姐的题解:
固定一颗生成树,加非树边 (u, v)
相当于把 uu
到 v
路径上的边涂黑,询问相当于询问路径上白边的数量。
用一个并查集 j(u)
维护点 u
向上第一条白边的位置,每次修改的时候暴力沿着 j(*)
找。
之后用树状数组维护 u
到路径上白边的数量,涂黑一条白边相当于子树整体减 1。
由于只有n个点,所以暴力合并的时候最多只会合并n次。
然后维护路径可以用树链剖分+线段树,但是这个是双log的,比较慢。
叉姐这样的维护方式只有1个log。
所以总体复杂度就是nlogn。
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=(a);i<=(b);++i) 3 using namespace std; 4 typedef pair<int,int>P; 5 #define mst(a,b) memset(a,b,sizeof(a)) 6 7 const int N=1e5+7; 8 int t,n,m,q,sum[N],cas,f[N]; 9 int nxt[2*N],g[N],v[2*N],ed,x,y,op; 10 int hs[N],fa[N],top[N],dep[N],sz[N],dfsl[N],dfsr[N],idx; 11 vector<P>edge; 12 13 void adg(int x,int y){v[++ed]=y,nxt[ed]=g[x],g[x]=ed;} 14 15 void dfs1(int u,int pre){ 16 dfsl[u]=++idx,dep[u]=dep[pre]+1,hs[u]=0,fa[u]=pre,sz[u]=1; 17 for(int i=g[u];i;i=nxt[i])if(v[i]!=pre) 18 dfs1(v[i],u),sz[u]+=sz[v[i]],hs[u]=(sz[v[i]]>sz[hs[u]])?v[i]:hs[u]; 19 dfsr[u]=idx; 20 } 21 void dfs2(int u,int tp){ 22 top[u]=tp; 23 if(hs[u])dfs2(hs[u],tp); 24 for(int i=g[u];i;i=nxt[i]) 25 if(v[i]!=fa[u]&&v[i]!=hs[u])dfs2(v[i],v[i]); 26 } 27 28 int LCA(int x,int y) 29 { 30 while(top[x]!=top[y]) 31 dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]; 32 return dep[x]<dep[y]?x:y; 33 } 34 35 inline void add(int x,int c){while(x<=n)sum[x]+=c,x+=x&-x;} 36 inline int ask(int x){int an=0;while(x)an+=sum[x],x-=x&-x;return an;} 37 38 inline int find(int x){return x==f[x]?x:f[x]=find(f[x]);} 39 void merge(int x,int y){f[find(x)]=find(y);} 40 41 void addedge(int x,int y) 42 { 43 int fx=find(x),fy=find(y); 44 if(fx==fy)return; 45 int lca=find(LCA(x,y)); 46 while(find(x)!=find(lca)) 47 { 48 add(dfsl[fx=find(x)],1); 49 add(dfsr[fx]+1,-1); 50 merge(fx,fa[fx]); 51 } 52 while(find(y)!=find(lca)) 53 { 54 add(dfsl[fy=find(y)],1); 55 add(dfsr[fy]+1,-1); 56 merge(fy,fa[fy]); 57 } 58 } 59 60 int main(){ 61 scanf("%d",&t); 62 while(t--) 63 { 64 printf("Case #%d:\n",++cas); 65 scanf("%d%d",&n,&m); 66 edge.clear(),mst(g,0),ed=0; 67 F(i,1,n)f[i]=i,sum[i]=0; 68 F(i,1,m) 69 { 70 scanf("%d%d",&x,&y); 71 if(find(x)!=find(y))adg(x,y),adg(y,x),merge(x,y); 72 else edge.push_back(P(x,y)); 73 } 74 idx=0,dfs1(1,0),dfs2(1,1); 75 F(i,1,n)f[i]=i; 76 for(auto &it:edge)addedge(it.first,it.second); 77 scanf("%d",&q); 78 while(q--) 79 { 80 scanf("%d%d%d",&op,&x,&y); 81 if(op==1)addedge(x,y); 82 else 83 { 84 int lca=LCA(x,y); 85 printf("%d\n",dep[x]+dep[y]-2*dep[lca]-(ask(dfsl[x])+ask(dfsl[y])-2*ask(dfsl[lca]))); 86 } 87 } 88 } 89 return 0; 90 }