【openjudge】C15C Rabbit's Festival CDQ分治+并查集
题目链接:http://poj.openjudge.cn/practice/C15C/
题意:n 点 m 边 k 天。每条边在某一天会消失(仅仅那一天消失)。问每一天有多少对点可以相互到达。
解法:开始不会做,参考的YYN的题解:http://blog.csdn.net/u013368721/article/details/45725181
学习了这种CDQ加并查集的做法,可以说是非常的巧妙了。复杂度可以保证在:O(KlogklogK)的范围。
//CDQ + DSU #include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 100010; const int maxe = 200010; struct edge{ int u,v,next; edge(){} edge(int u,int v,int next):u(u),v(v),next(next){} }E[maxn*2]; int n, m, k, head[maxn], edgecnt; struct Node{ int u,v,cntu,cntv,rnku,rnkv; Node(){} Node(int u,int v,int cntu,int cntv,int rnku,int rnkv):u(u),v(v),cntu(cntu),cntv(cntv),rnku(rnku),rnkv(rnkv){} }; Node S[maxe]; int cnt[maxn]; int p[maxn]; int rnk[maxn]; int top; LL ans; void init(){ top = 0; ans = 0; edgecnt=0; memset(head,-1,sizeof(head)); } void add(int id , int u, int v){ E[edgecnt] = edge (u, v, head[id]); head[id] = edgecnt++; } int find_set(int x){ int o = x; while(p[o] != o) o = p[o]; return o; } void union_set(int l, int r){ for(int t=l; t<=r; t++){ for(int i=head[t]; ~i; i=E[i].next){ int u = find_set(E[i].u); int v = find_set(E[i].v); if(u == v) continue; S[top++] = Node(u, v, cnt[u], cnt[v], rnk[u], rnk[v]); ans += (LL)cnt[u] * cnt[v]; if(rnk[u] <= rnk[v]){ rnk[v] = max(rnk[v], rnk[u]+1); p[u] = v; cnt[v] += cnt[u]; } else{ p[v] = u; cnt[u] += cnt[v]; } } } } void Back(int x) { while(top > x){ --top; int u = S[top].u, v = S[top].v; ans -= (LL)S[top].cntu*S[top].cntv; p[u] = u; p[v] = v; cnt[u] = S[top].cntu; cnt[v] = S[top].cntv; rnk[u] = S[top].rnku; rnk[v] = S[top].rnkv; } } void CDQ(int l, int r) { if(l == r){ printf("%lld\n", ans); return; } int mid=(l+r)>>1; int rtop=top; union_set(mid+1,r); CDQ(l, mid); Back(rtop); union_set(l,mid); CDQ(mid+1,r); Back(rtop); } int main() { while(~scanf("%d %d %d", &n,&m,&k)) { init(); for(int i=1; i<=n; i++){ p[i]=i; cnt[i]=1; rnk[i]=0; } int u, v, c; for(int i=1; i<=m; i++){ scanf("%d %d %d", &u,&v,&c); if(c > k){ u = find_set(u), v = find_set(v); if(u == v) continue; if(rnk[u]<=rnk[v]){ rnk[v]=max(rnk[v],rnk[u]+1); p[u]=v; cnt[v]+=cnt[u]; } else{ p[v]=u; cnt[u]+=cnt[v]; } } else{ add(c, u, v); } } CDQ(1, k); } return 0; }