hdu5458 LCA+並查集+樹狀陣列
阿新 • • 發佈:2019-02-12
題意:給出n個點、m條邊(可能有環、重邊)、q個詢問~~
詢問1:=刪除某一條邊<a,b>
詢問2:=問<a,b>路徑中有多少條橋~~~
橋、如果將環收縮的話,圖會變成一個樹。那麼有多少條橋也就是問路徑<a,b>的大小。
即deep[a]+deep[b]-a*deep[lca(a,b)].
首先圖是刪邊的,很麻煩~~所有離線逆過來處理。
對於要“新增的邊“先標記。
利用剩下的沒有動過的邊跑一趟dfs序成一個完整的樹
並記錄下deep[](深度),當前節點對應的編號idx、當前節點子樹的區間lr[u]....
然後利用剛才沒有用過的非新增的邊進行縮點,當每減少一條橋,某一刻孩子樹將會往上提高一個高度。
這個資訊可以用樹狀陣列進行維護~~~~
同時也用一個並查集維護縮點資訊~~~
#include <algorithm> #include <iostream> #include<string.h> #include <fstream> #include <math.h> #include <vector> #include <cstdio> #include <string> #include <queue> #include <stack> #include <map> #include <set> #define exp 1e-8 #define fi first #define se second #define ll long long #define INF 0x3f3f3f3f #define pb(a) push_back(a) #define mp(a,b) make_pair(a,b) #define all(a) a.begin(),a.end() #define mm(a,b) memset(a,b,sizeof(a)); #define for1(a,b) for(int a=1;a<=b;a++)//1---(b) #define rep(a,b,c) for(int a=b;a<=c;a++)//b---c #define repp(a,b,c)for(int a=b;a>=c;a--)/// #define stl(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++) using namespace std; void bug(string m="here"){cout<<m<<endl;} template<typename __ll> inline void READ(__ll &m){__ll x=0,f=1;char ch=getchar();while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}m=x*f;} template<typename __ll>inline void read(__ll &m){READ(m);} template<typename __ll>inline void read(__ll &m,__ll &a){READ(m);READ(a);} template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);} template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c){READ(m);READ(a);READ(b);READ(c);} template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c,__ll &d){READ(m);READ(a);READ(b);READ(c);read(d);} template < class T > T gcd(T a, T b) { return b ? gcd(b, a % b) : a; } template < class T > T lcm(T a, T b) { return a / gcd(a, b) * b; } template < class T > inline void rmin(T &a, const T &b) { if(a > b) a = b; } template < class T > inline void rmax(T &a, const T &b) { if(a < b) a = b; } template < class T > T pow(T a, T b) { T r = 1; while(b > 0) { if(b & 1) r = r * a; a = a * a; b /= 2; } return r; } template < class T > T pow(T a, T b, T mod) { T r = 1; while(b > 0) { if(b & 1) r = r * a % mod; a = a * a % mod; b /= 2; } return r; } const int maxn=30010; int n,m,q; int idx[maxn]; int kk,lr[maxn][3]; int deep[maxn]; int fa[maxn][20]; int belong[maxn]; struct edge { int v,del; edge(){} edge(int vv){v=vv,del=0;} bool operator < (const edge &rhs) const{ if(v!=rhs.v)return v<rhs.v; return del>rhs.del; } }; vector<edge>vec[maxn]; struct QUERY { int op,a,b,ans; void READ() { read(op,a,b); ans=-1; if(op==1) { lower_bound(all(vec[a]),edge(b))->del=1; lower_bound(all(vec[b]),edge(a))->del=1; } } }query[100010]; void init() { kk=1; for1(i,n)vec[i].clear(); for1(i,n)belong[i]=i; memset(deep,0,sizeof deep); } void dfs_id(int u,int ff,int dee) { deep[u]=dee; fa[u][0]=ff; lr[u][1]=kk; for(int i=0;i<vec[u].size();i++) { if(vec[u][i].del==1)continue; int v=vec[u][i].v; if(v==ff) { vec[u].erase(vec[u].begin()+i);///刪除與父親的聯絡啦~~~~ i--; continue; } if(deep[v]!=0)continue; vec[u].erase(vec[u].begin()+i);///刪除與孩子的聯絡啦~~~~ i--; dfs_id(v,u,dee+1); } idx[u]=lr[u][2]=kk++; } struct LCA { void init() { ///p[i][j]表示i結點的第2^j祖先 for(int j=1;(1<<j)<=n;j++) for(int i=1;i<=n;i++) if(fa[i][j-1]!=-1) fa[i][j]=fa[fa[i][j-1]][j-1];///i的第2^j祖先就是i的第2^(j-1)祖先的第2^(j-1)祖先 } int ask(int a,int b)///最近公共祖先 { int i,j; if(deep[a]<deep[b])swap(a,b); for(i=0;(1<<i)<=deep[a];i++); i--; ///使a,b兩點的深度相同 for(j=i;j>=0;j--) if(deep[a]-(1<<j)>=deep[b]) a=fa[a][j]; if(a==b)return a; ///倍增法,每次向上進深度2^j,找到最近公共祖先的子結點 for(j=i;j>=0;j--) { if(fa[a][j]!=-1&&fa[a][j]!=fa[b][j]) { a=fa[a][j]; b=fa[b][j]; } } return fa[a][0]; } }lca; struct bit_tree { int Tree[maxn]; inline int lowbit(int x){return x&-x;} void init() { memset(Tree,0,sizeof Tree); } void modify(int x,int y,int val) { doit(x,val); doit(y+1,-val); } void doit(int x,int val) { for(int i=x;i<=n;i+=lowbit(i)) //n為區間總長度,1---n Tree[i]+=val; } int sum(int x) { int res=0; for(int i=x;i>0;i-=lowbit(i)) res+=Tree[i]; return res; } }tree; int find(int k) { if(belong[k]!=k) belong[k]=find(belong[k]); return belong[k]; } void merge_fa(int a,int b) { a=find(a); b=find(b); while(a!=b) { int par=find(fa[a][0]);/// belong[a]=par; tree.modify(lr[a][1],lr[a][2],-1); a=par; } } void merge(int a,int b) { int l=lca.ask(a,b); merge_fa(a,l); merge_fa(b,l); } void merge_ret() { for(int u=1;u<=n;u++) for(int i=0;i<vec[u].size();i++) { if(vec[u][i].del==1)continue; merge(u,vec[u][i].v); } } int get_ans(int a,int b) { int l=lca.ask(a,b); int nowa=deep[a]+tree.sum(idx[a]); int nowb=deep[b]+tree.sum(idx[b]); int nowl=deep[l]+tree.sum(idx[l]); return nowa+nowb-2*nowl; } void solve() { tree.init(); dfs_id(1,1,1); lca.init(); merge_ret(); for(int i=q;i>=1;i--) { if(query[i].op==1) merge(query[i].a,query[i].b); else query[i].ans=get_ans(query[i].a,query[i].b); } for1(i,q)if(query[i].ans!=-1)printf("%d\n",query[i].ans); } int main() { int cas; read(cas); for1(tt,cas) { read(n,m,q); init(); for1(i,m) { int a,b;read(a,b); vec[a].pb(edge(b)); vec[b].pb(edge(a)); } for1(i,n)sort(all(vec[i])); for1(i,q)query[i].READ(); printf("Case #%d:\n", tt); solve(); } }