loj 121 「离线可过」动态图连通性

这是一道被离线爆艹的模板题。

你要维护一张无向简单图。你被要求加入删除一条边及查询两个点是否连通。

  • 0:加入一条边。保证它不存在。
  • 1:删除一条边。保证它存在。
  • 2:查询两个点是否联通。

 

本题解法: 

1.lct

2.对操作进行分块,然后维护并查集(需要回到过去)。  时间复杂度$O(m*sqrt(m)*logn)$ 

由于时限只有800ms,时间复杂度比较高,我优化了半天,也只能有93分。 

  1 #pragma GCC optimize(3)
  2 #include<bits/stdc++.h>
  3 using namespace std;  
  4 int const N=5000+10;  
  5 int const M=500000+10;  
  6 int const B=1000; 
  7 #define st(x) (((x)-1)*B+1)   
  8 #define ed(x) min(m,(x)*B)  
  9 #define bl(x) (((x)-1)/B+1)  
 10 #define pii   pair<int,int>  
 11 #define mp    make_pair  
 12 #define Find(x) { while (x!=f[x]) x=f[x]; }
 13 int n,m,f[N],s[N],x[M],y[M],z[M],st[N],top;   
 14 set<pii> mat,mt,se; 
 15 set<pii> :: iterator p;  
 16 char gc()
 17 {
 18     static char buf[100000000],*p1=buf,*p2=buf;
 19     return p1==p2&&(p2=(p1=buf)+fread(buf,1,10000000,stdin),p1==p2)?EOF:*p1++;
 20 }
 21 template<typename __Type_of__scan>
 22 void read(__Type_of__scan &x)
 23 {
 24     __Type_of__scan f=1;x=0;char s=gc();
 25     while(s<'0'||s>'9'){if(s=='-')f=-1;s=gc();}
 26     while(s>='0'&&s<='9'){x=x*10+s-'0';s=gc();}
 27     x*=f;
 28 }     
 29 int main(){
 30     freopen("graph6.in","r",stdin); 
 31     freopen("std.out","w",stdout); 
 32     read(n); read(m);    
 33     int tot=bl(m);  
 34     for(int i=1;i<=tot;i++){
 35         int beg=st(i),end=ed(i); 
 36         se.clear(); mt.clear();  
 37         int cnt=0; 
 38         for(register int j=beg;j<=end;j++){
 39             read(z[j]);read(x[j]); read(y[j]); 
 40             if(z[j]==2){
 41                 cnt++; continue; 
 42             } 
 43             if(x[j]>y[j]) swap(x[j],y[j]);  
 44             se.insert(mp(x[j],y[j]));  
 45         }
 46         for(register int j=1;j<=n;j++) f[j]=j,s[j]=1;  
 47         if(i>1){
 48             int bb=st(i-1),ee=ed(i-1);  
 49             for(register int j=bb;j<=ee;j++) {
 50                 if(z[j]==2) continue;  
 51                 if(mat.find(mp(x[j],y[j]))!=mat.end())  
 52                     mat.erase(mp(x[j],y[j]));  
 53                 else 
 54                     mat.insert(mp(x[j],y[j]));  
 55             }
 56         } 
 57         if(cnt==0) continue;  
 58         for(p=mat.begin();p!=mat.end();p++){
 59             if(se.find(*p)!=se.end()) {
 60                 mt.insert(*p);  
 61                 continue;  
 62             }
 63             int fx=p->first;  
 64             int fy=p->second;  
 65             Find(fx);Find(fy); 
 66             if(fx!=fy){
 67                 if(s[fx]>s[fy]) swap(fx,fy);  
 68                 f[fx]=fy;  
 69                 s[fy]+=s[fx];  
 70             }
 71         }
 72         top=0;  
 73         for(register int j=beg;j<=end;j++){
 74             if(z[j]<2){
 75                 if(mt.find(mp(x[j],y[j]))==mt.end())  
 76                     mt.insert(mp(x[j],y[j])); 
 77                 else   
 78                     mt.erase(mp(x[j],y[j])); 
 79             }else { 
 80                 for( p=mt.begin();p!=mt.end();p++){
 81                         int fx=p->first;   
 82                         int fy=p->second;      
 83                         Find(fx);Find(fy);  
 84                         if(fx!=fy){
 85                             if(s[fx]>s[fy]) swap(fx,fy);  
 86                             f[fx]=fy;  
 87                             s[fy]+=s[fx];  
 88                             st[++top]=fx;  
 89                         }
 90                 }
 91                 int fx=x[j]; 
 92                 int fy=y[j]; 
 93                 Find(fx);Find(fy);   
 94                 puts(fx==fy? "Y":"N");  
 95                 while (top) {
 96                     int t=st[top];  
 97                     s[f[t]]-=s[t];  
 98                     f[t]=t;  
 99                     top--; 
100                 }
101             }
102         }
103     }
104     return 0; 
105 } 
View Code

 

3.线段树分治+ 并查集 时间复杂度$O(m*logm*logm) $ 

 1 #include<bits/stdc++.h>
 2 using namespace std; 
 3 int const N=5000+10;  
 4 int const M=500000+10;  
 5 #define pii pair<int,int>
 6 #define mid (l+r)/2 
 7 #define lc  (x<<1)  
 8 #define rc  (x<<1|1)  
 9 int n,m,f[N],s[N],st[N],tp,ans[M]; 
10 pii q[M];  
11 map<pii,int> mp;  
12 map<pii,int> :: iterator it;  
13 vector<pii> v[M*4]; 
14 int find(int x){
15     return x==f[x]? x: find(f[x]);  
16 }   
17 void merge(int x,int y){
18     x=find(x); y=find(y);  
19     if(x==y) return;  
20     if(s[x]>s[y]) swap(x,y);  
21     f[x]=y;  s[y]+=s[x];  st[++tp]=x;  
22 }
23 
24 void change(int x,int l,int r,int ll,int rr,pii d){
25     if(ll<=l && r<=rr){
26         v[x].push_back(d); return;  
27     }
28     if(ll<=mid) change(lc,l,mid,ll,rr,d);  
29     if(rr>mid)  change(rc,mid+1,r,ll,rr,d);  
30 }
31 void link(int x,int y,int ti){
32     if(x>y) swap(x,y);  
33     mp[make_pair(x,y)]=ti;  
34 }  
35 void cut(int x,int y,int ti){
36     if(x>y) swap(x,y);  
37     pii p=make_pair(x,y);  
38     change(1,1,m,mp[p],ti-1,p);  
39     mp[p]=0;  
40 }
41 void undo(int t){
42     while (tp>t){
43         int x=st[tp--];  
44         s[f[x]]-=s[x];   
45         f[x]=x;  
46     }
47 }
48 
49 void solve(int x,int l,int r){
50     int tp1=tp;  
51     for(int i=0;i<v[x].size();i++) {
52         int xx=v[x][i].first,yy=v[x][i].second;  
53         merge(xx,yy);  
54     }
55     if(l==r){
56         if(q[l].first) ans[l]=find(q[l].first)==find(q[l].second);  
57         undo(tp1); return;  
58     }
59     solve(lc,l,mid);  
60     solve(rc,mid+1,r);  
61     undo(tp1);  
62 }
63 
64 
65 int main(){
66     scanf("%d%d",&n,&m);  
67     for(int i=1;i<=n;i++) f[i]=i,s[i]=1;  
68     for(int i=1;i<=m;i++){
69         int op,x,y;  
70         scanf("%d%d%d",&op,&x,&y);  
71         if(op==0) link(x,y,i);  
72         else if(op==1) cut(x,y,i);  
73         else q[i]=make_pair(x,y);  
74     }
75     for(it=mp.begin();it!=mp.end();it++){
76         if((*it).second!=0) {
77             pii p=(*it).first;   
78             cut(p.first,p.second,m+1);  
79         }
80     }
81     solve(1,1,m);  
82     for(int i=1;i<=m;i++) if(q[i].first)  
83         puts(ans[i]? "Y":"N");  
84     return 0;  
85 }  
View Code

 

转载于:https://www.cnblogs.com/ZJXXCN/p/11561217.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值