[SHOI2008]堵塞的交通traffic

我是萌萌的传送门

这题说白了就是一个支持加边和删边的图连通性维护,不过鉴于图的特殊性,可以直接线段树(听说标算就是这个……)。

然而我人比较懒,不想思考怎么线段树,于是乎写了一发分治并查集,1A我真是感动……

话说一时没想起来怎么写能撤销的按秩合并,于是乎写了个随机合并(反正期望复杂度都是logn的),代码开头那个玩意儿就是手写的随机数生成器……(我会说模数取998244353之后即使int有溢出也能保证循环节在一千万以上嘛……)

第一发分治并查集,又学会了一个新技能哈哈……

话说这份代码在bzoj上被卡了,真是忧伤……

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<vector>
  5 #include<map>
  6 using namespace std;
  7 const int maxn=100010;
  8 inline int randint(){
  9     static int a=151,b=24863,c=9788417,x=1089488183,p=998244353;
 10     x=a*x*x+b*x+c;x%=p;
 11     return x<0?(x=-x):x;
 12 }
 13 struct A{int u,v,tp;}a[maxn];
 14 void addedge(int,int,int);
 15 void addquery(int,int,int);
 16 void solve(int,int,int);
 17 int findroot(int);
 18 void mergeset(int,int,vector<int>&);
 19 int id[3][maxn],cnt=0,prt[maxn<<1],qu[maxn<<2],qv[maxn<<2];
 20 int n,m=1,x1,y1,x2,y2,x,y,s,t;
 21 vector<int>u[maxn<<2],v[maxn<<2],stk[maxn<<2];
 22 map<pair<int,int>,int>mp;
 23 char c[15];
 24 int main(){
 25     freopen("bzoj_1018.in","r",stdin);
 26     freopen("bzoj_1018.out","w",stdout);
 27     scanf("%d",&n);
 28     for(int i=1;i<=n;i++){
 29         id[1][i]=++cnt;
 30         id[2][i]=++cnt;
 31     }
 32     for(int i=1;i<=cnt;i++)prt[i]=i;
 33     for(int &i=m;scanf("%s",c)==1&&strcmp(c,"Exit");i++){
 34         scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
 35         x=id[x1][y1];y=id[x2][y2];
 36         if(x>y)swap(x,y);
 37         a[i].u=x;a[i].v=y;
 38         if(!strcmp(c,"Open"))a[i].tp=1;
 39         else if(!strcmp(c,"Close"))a[i].tp=2;
 40         else a[i].tp=3;
 41     }
 42     for(int i=1;i<=m;i++){
 43         x=a[i].u;y=a[i].v;
 44         if(a[i].tp==1){
 45             if(!mp.count(make_pair(x,y)))mp[make_pair(x,y)]=i;
 46         }
 47         else if(a[i].tp==2){
 48             if(mp.count(make_pair(x,y))){
 49                 s=mp[make_pair(x,y)];
 50                 t=i;
 51                 addedge(1,m,1);
 52                 mp.erase(make_pair(x,y));
 53             }
 54         }
 55         else{
 56             t=i;
 57             addquery(1,m,1);
 58         }
 59     }
 60     for(map<pair<int,int>,int>::iterator it=mp.begin();it!=mp.end();it++){
 61         x=it->first.first;
 62         y=it->first.second;
 63         s=it->second;
 64         t=m;
 65         addedge(1,m,1);
 66     }
 67     solve(1,m,1);
 68     return 0;
 69 }
 70 void addedge(int l,int r,int rt){
 71     if(s<=l&&t>=r){
 72         u[rt].push_back(x);
 73         v[rt].push_back(y);
 74         return;
 75     }
 76     int mid=(l+r)>>1;
 77     if(s<=mid)addedge(l,mid,rt<<1);
 78     if(t>mid)addedge(mid+1,r,rt<<1|1);
 79 }
 80 void addquery(int l,int r,int rt){
 81     if(l==r){
 82         qu[rt]=x;
 83         qv[rt]=y;
 84         return;
 85     }
 86     qu[rt]|=x;
 87     int mid=(l+r)>>1;
 88     if(t<=mid)addquery(l,mid,rt<<1);
 89     else addquery(mid+1,r,rt<<1|1);
 90 }
 91 void solve(int l,int r,int rt){
 92     if(!qu[rt])return;
 93     for(int i=0;i<(int)u[rt].size();i++)mergeset(u[rt][i],v[rt][i],stk[rt]);
 94     if(l==r)printf(findroot(qu[rt])==findroot(qv[rt])?"Y\n":"N\n");
 95     else{
 96         int mid=(l+r)>>1;
 97         solve(l,mid,rt<<1);
 98         solve(mid+1,r,rt<<1|1);
 99     }
100     if(!stk[rt].empty())for(int i=(int)stk[rt].size()-1;i>=0;i--)prt[stk[rt][i]]=stk[rt][i];
101 }
102 int findroot(int x){
103     while(prt[x]!=x)x=prt[x];
104     return x;
105 }
106 void mergeset(int x,int y,vector<int>&a){
107     x=findroot(x);y=findroot(y);
108     if(x==y)return;
109     if(randint()&1)swap(x,y);
110     prt[x]=y;
111     a.push_back(x);
112 }
View Code

不知道该加什么分类了,反正是对时间建线段树,加到CDQ分治里算了……

posted @ 2016-12-24 18:43  AntiLeaf  阅读(123)  评论(0编辑  收藏  举报