poj3694 Network[边双缩点+树剖/并查集]

首先同一个点双内部的加边肯定不影响。。所以先缩点成树,然后每次加一条边,这条对应的树上路径上所有边就都不是桥了,且每次操作独立作用,不相互影响(不过有可能本来一条边已经不是桥了又被标记了一次),所以每次相当对树链做一次链覆盖,统计未覆盖边。这个是链剖板子。。$O(N\log^2N)$

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 #include<queue>
  7 #define mst(x) memset(x,0,sizeof x)
  8 #define dbg(x) cerr << #x << " = " << x <<endl
  9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
 10 using namespace std;
 11 typedef long long ll;
 12 typedef double db;
 13 typedef pair<int,int> pii;
 14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
 15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
 16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
 17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
 18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
 19 template<typename T>inline T read(T&x){
 20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c==‘-‘)f=1;
 21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
 22 }
 23 const int N=1e5+7;
 24 int n,m,q,cas,fir;
 25 struct thxorz{
 26     int head[N],nxt[N<<2],to[N<<2],tot;
 27     inline void add(int x,int y){
 28         to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
 29         to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
 30     }
 31     #define y to[j]
 32     int dfn[N],low[N],cut[N<<2],bel[N],tim,dcc;
 33     void tarjan(int x,int las){
 34         dfn[x]=low[x]=++tim;
 35         for(register int j=head[x];j;j=nxt[j])if(j^(las^1)){
 36             if(!dfn[y]){
 37                 tarjan(y,j),MIN(low[x],low[y]);
 38                 if(low[y]>dfn[x])cut[j]=cut[j^1]=1;
 39             }
 40             else MIN(low[x],dfn[y]);
 41         }
 42     }
 43     void dfs(int x){
 44         bel[x]=dcc;//dbg2(x,dcc);
 45         for(register int j=head[x];j;j=nxt[j])if(!cut[j]&&!bel[y])dfs(y);
 46     }
 47     #undef y
 48     inline void clear(){mst(head),mst(dfn),mst(cut),mst(bel),tim=dcc=0,tot=1;}
 49 }G;
 50 struct uuzlovetree{
 51     int head[N],nxt[N<<1],to[N<<1],tot;
 52     inline void add(int x,int y){
 53         to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
 54         to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
 55     }
 56     #define y to[j]
 57     int fa[N],topfa[N],cnt[N],son[N],pos[N],dep[N],tim;
 58     void dfs1(int x,int fat){//dbg(x);
 59         fa[x]=fat,cnt[x]=1,dep[x]=dep[fat]+1;int tmp=-1;
 60         for(register int j=head[x];j;j=nxt[j])if(y^fat)dfs1(y,x),cnt[x]+=cnt[y],MAX(tmp,cnt[y])&&(son[x]=y);
 61     }
 62     void dfs2(int x,int topf){
 63         topfa[x]=topf,pos[x]=++tim;if(!son[x])return;dfs2(son[x],topf);
 64         for(register int j=head[x];j;j=nxt[j])if(y^fa[x]&&y^son[x])dfs2(y,y);
 65     }
 66     #undef y
 67     int tag[N<<2],sumv[N<<2];
 68     #define lc i<<1
 69     #define rc i<<1|1
 70     inline void pushup(int i){sumv[i]=sumv[lc]+sumv[rc];}
 71     inline void pushdown(int i){
 72         if(tag[i])tag[lc]=tag[rc]=1,sumv[lc]=sumv[rc]=0,tag[i]=0;
 73     }
 74     void Build(int i,int L,int R){//dbg(i),dbg2(L,R);
 75         if(L==R){sumv[i]=1;tag[i]=0;return;}
 76         int mid=L+R>>1;
 77         Build(lc,L,mid),Build(rc,mid+1,R);pushup(i);
 78     }
 79     void Update(int i,int L,int R,int ql,int qr){
 80         if(ql<=L&&qr>=R){tag[i]=1,sumv[i]=0;return;}
 81         int mid=L+R>>1;
 82         pushdown(i);
 83         if(ql<=mid)Update(lc,L,mid,ql,qr);
 84         if(qr>mid)Update(rc,mid+1,R,ql,qr);
 85         pushup(i);
 86     }
 87     #undef lc
 88     #undef rc
 89     inline void tree_update(int x,int y){
 90         while(topfa[x]^topfa[y]){
 91             if(dep[topfa[x]]<dep[topfa[y]])_swap(x,y);
 92             Update(1,2,tim,pos[topfa[x]],pos[x]),x=fa[topfa[x]];
 93         }
 94         if(dep[y]<dep[x])_swap(x,y);
 95         if(x^y)Update(1,2,tim,pos[x]+1,pos[y]);
 96     }
 97     inline void clear(){mst(head),mst(tag),mst(sumv),mst(son),tim=tot=0;}
 98 }T;
 99
100 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
101     while(read(n),read(m),n||m){
102         G.clear(),T.clear();
103         for(register int i=1,x,y;i<=m;++i)read(x),read(y),G.add(x,y);
104         for(register int i=1;i<=n;++i)if(!G.dfn[i])G.tarjan(i,0);
105         for(register int i=1;i<=n;++i)if(!G.bel[i])++G.dcc,G.dfs(i);
106         for(register int t=2;t<=G.tot;t+=2){
107             int x=G.to[t],y=G.to[t^1];
108             if(G.bel[x]^G.bel[y])T.add(G.bel[x],G.bel[y]);//dbg2(G.bel[x],G.bel[y]);
109         }
110         T.dfs1(1,0);T.dfs2(1,1);
111         T.Build(1,2,T.tim);
112         read(q);if(fir)puts("");fir=1;
113         printf("Case %d:\n",++cas);
114         for(register int i=1,x,y;i<=q;++i){
115             read(x),read(y);T.tree_update(G.bel[x],G.bel[y]);
116             printf("%d\n",T.sumv[1]);
117         }
118     }
119     return 0;
120 }

链剖

发现自己数据结构学傻掉了。。完全不需要的说。。因为每次加边的时候这个链就是一个环了对不对。。然后实际上可以看成再缩成一个大点,然后每次询问只要暴力往上爬到lca就好了。。具体实现的话呢,使用并查集来合并的,爬过的所有点(不管是原点还是后来的缩的点)都合并起来,所谓的看成大点就是把所有点所在的这个集合的根设为这个块最顶端的点,这样既方便合并,也方便跳,每次虽然是暴力跳的,但是每跳一次就会合并一次,合并$n$次,需要跳的越来越少,所以爬是线性的。。。但是被两个$\log$的链剖吊打了?

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<queue>
 7 #define mst(x) memset(x,0,sizeof x)
 8 #define dbg(x) cerr << #x << " = " << x <<endl
 9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
10 using namespace std;
11 typedef long long ll;
12 typedef double db;
13 typedef pair<int,int> pii;
14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
19 template<typename T>inline T read(T&x){
20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c==‘-‘)f=1;
21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
22 }
23 const int N=1e5+7;
24 int n,m,q,cas,fir,ans;
25 struct thxorz{
26     int head[N],nxt[N<<2],to[N<<2],tot;
27     inline void add(int x,int y){
28         to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
29         to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
30     }
31     #define y to[j]
32     int dfn[N],low[N],cut[N<<2],bel[N],tim,dcc;
33     void tarjan(int x,int las){
34         dfn[x]=low[x]=++tim;
35         for(register int j=head[x];j;j=nxt[j])if(j^(las^1)){
36             if(!dfn[y]){
37                 tarjan(y,j),MIN(low[x],low[y]);
38                 if(low[y]>dfn[x])cut[j]=cut[j^1]=1;
39             }
40             else MIN(low[x],dfn[y]);
41         }
42     }
43     void dfs(int x){
44         bel[x]=dcc;//dbg2(x,dcc);
45         for(register int j=head[x];j;j=nxt[j])if(!cut[j]&&!bel[y])dfs(y);
46     }
47     #undef y
48     inline void clear(){mst(head),mst(dfn),mst(cut),mst(bel),tim=dcc=0,tot=1;}
49 }G;
50 struct uuzlovetree{
51     int head[N],nxt[N<<1],to[N<<1],tot;
52     inline void add(int x,int y){
53         to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
54         to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
55     }
56     #define y to[j]
57     int fa[N],dep[N],n;
58     void dfs1(int x,int fat){//dbg(x);
59         fa[x]=fat,dep[x]=dep[fat]+1;
60         for(register int j=head[x];j;j=nxt[j])if(y^fat)dfs1(y,x);
61     }
62     #undef y
63     int anc[N];
64     int Find(int x){return anc[x]==x?x:anc[x]=Find(anc[x]);}
65     inline void stostostostothxorzorzorzorz(int x,int y){
66         x=Find(x),y=Find(y);
67         while(x^y){
68             if(dep[x]<dep[y])_swap(x,y);
69             int tmp=Find(fa[x]);
70             anc[x]=tmp,x=tmp;
71             --ans;
72         }
73     }
74     inline void clear(){mst(head),tot=n=0;}
75 }T;
76
77 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
78     while(read(n),read(m),n||m){
79         G.clear(),T.clear();
80         for(register int i=1,x,y;i<=m;++i)read(x),read(y),G.add(x,y);
81         for(register int i=1;i<=n;++i)if(!G.dfn[i])G.tarjan(i,0);
82         for(register int i=1;i<=n;++i)if(!G.bel[i])++G.dcc,G.dfs(i);
83         for(register int t=2;t<=G.tot;t+=2){
84             int x=G.to[t],y=G.to[t^1];
85             if(G.bel[x]^G.bel[y])T.add(G.bel[x],G.bel[y]);//dbg2(G.bel[x],G.bel[y]);
86         }
87         T.dfs1(1,0);ans=G.dcc-1;
88         for(register int i=1;i<=G.dcc;++i)T.anc[i]=i;
89         read(q);if(fir)puts("");fir=1;
90         printf("Case %d:\n",++cas);
91         for(register int i=1,x,y;i<=q;++i){
92             read(x),read(y);
93             T.stostostostothxorzorzorzorz(G.bel[x],G.bel[y]);
94             printf("%d\n",ans);
95         }
96     }
97     return 0;
98 }

dsu

原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11736043.html

时间: 2024-08-28 19:01:32

poj3694 Network[边双缩点+树剖/并查集]的相关文章

POJ 2236 Wireless Network ||POJ 1703 Find them, Catch them 并查集

POJ 2236 Wireless Network http://poj.org/problem?id=2236 题目大意: 给你N台损坏的电脑坐标,这些电脑只能与不超过距离d的电脑通信,但如果x和y均能C通信,则x和y可以通信.现在给出若干个操作, O p 代表修复编号为p的电脑 S p q代表询问p和q是不是能通信. 思路: 并查集即可.. 如果修复了一台电脑,则把与它相连距离不超过d的且修复了的放在一个集合里面. #include<cstdio> #include<cstring&

POJ 2513 Colored Sticks(欧拉回路,字典树,并查集)

题意:给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的. 转:kuangbing 无向图存在欧拉路的充要条件为: ①     图是连通的: ②     所有节点的度为偶数,或者有且只有两个度为奇数的节点. 图的连通可以利用并查集去判断. 度数的统计比较容易. view code//第一次用指针写trie,本来是用二维数组,发现数组开不下,只好删删改改,改成指针 //做这道题,知道了欧拉回路判定,还有用指针写trie #include

POJ2513:Colored Sticks(字典树+欧拉路径+并查集)

http://poj.org/problem?id=2513 Description You are given a bunch of wooden sticks. Each endpoint of each stick is colored with some color. Is it possible to align the sticks in a straight line such that the colors of the endpoints that touch are of t

[BZOJ4025]二分图(线段树分治,并查集)

4025: 二分图 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2191  Solved: 800[Submit][Status][Discuss] Description 神犇有一个n个节点的图.因为神犇是神犇,所以在T时间内一些边会出现后消失.神犇要求出每一时间段内这个图是否是二分图.这么简单的问题神犇当然会做了,于是他想考考你. Input 输入数据的第一行是三个整数n,m,T. 第2行到第m+1行,每行4个整数u,v,start,end

[bzoj1455]罗马游戏_左偏树_并查集

罗马游戏 bzoj-1455 题目大意:给你n个人,2种操作,m次操作:1.将i号士兵所在的集合的最小值删除 2.合并i和j两个士兵所在的团体 注释:$1\le n\le 10^6$,$1\le m \le 10^5$. 想法:又是GXZlegend讲课,可并堆中的左偏树.了解一下: 一个具有堆性质的二叉树满足任意一个节点x中,dis[lson[x]]>=dis[rson[x]],其中,dis表示当前节点一直走右儿子的最长步数.合并是递归合并,我们通过递归处理一两个节点为根节点的左偏树的合并,显

HDU 6271 Master of Connected Component(2017 CCPC 杭州 H题,树分块 + 并查集的撤销)

题目链接  2017 CCPC Hangzhou Problem H 思路:对树进行分块.把第一棵树分成$\sqrt{n}$块,第二棵树也分成$\sqrt{n}$块.    分块的时候满足每个块是一个连通块,那么每个块就有一个共同的祖先. 把询问按照第一个点被第一棵树的哪个祖先管辖和第二个点被第二棵树的哪个祖先管辖,分成$n$类. 每一类询问一起处理,处理完后用可撤销并查集恢复到之前的状态. 每一类询问之间依次转移,每次转移,移动次数不会超过$\sqrt{n}$次. 最后总时间复杂度$O(n^{

线段树分治总结(线段树分治,线段树,并查集,树的dfn序,二分图染色)

闲话 stO猫锟学长,满脑子神仙DS 线段树分治思想 我们在做CDQ的时候,将询问和操作通通视为元素,在归并过程中统计左边的操作对右边的询问的贡献. 而在线段树分治中,询问被固定了.按时间轴确定好询问的序列以后,我们还需要所有的操作都会影响一个时间区间.而这个区间,毫无疑问正好对应着询问的一段区间. 于是,我们可以将每一个操作丢到若干询问里做区间修改了,而线段树可以高效地维护.我们开一个叶子节点下标为询问排列的线段树,作为分治过程的底层结构. 具体的实现,仍然要看题目. 例题1 BZOJ4025

Codeforces.1051G.Distinctification(线段树合并 并查集)

题目链接 \(Description\) 给定\(n\)个数对\(A_i,B_i\).你可以进行任意次以下两种操作: 选择一个位置\(i\),令\(A_i=A_i+1\),花费\(B_i\).必须存在一个位置\(j\),满足\(A_i=A_j,\ i\neq j\),才可以进行. 选择一个位置\(i\),令\(A_i=A_i-1\),花费\(-B_i\).必须存在一个位置\(j\),满足\(A_i=A_j+1\),才可以进行. 你需要对于所有\(i\in[1,n]\),求使得\(A_1,A_2,

Codeforces 1140F 线段树 分治 并查集

题意及思路:https://blog.csdn.net/u013534123/article/details/89010251 之前cf有一个和这个相似的题,不过那个题只有合并操作,没有删除操作,直接并查集搞一搞就行了.对于这个题,因为有删除操作,我们对操作序列建一颗线段树,记录每个操作影响的区间操作就可以了.这里的并查集不能路径压缩,要按秩合并,这样复杂度是O(logn)的. 代码: #include <bits/stdc++.h> #define ls (o << 1) #de