BZOJ1969: [Ahoi2005]LANE 航线规划
题解 :LCT动态缩环即可
/************************************************************** Problem: 1969 User: c20161007 Language: C++ Result: Accepted Time:856 ms Memory:6692 kb ****************************************************************/ #include <bits/stdc++.h> #define ll long long const int MAXN=3e4+10; const int NM=1e5+10; using namespace std; int rt[MAXN],size[MAXN],minn[MAXN],ch[MAXN][2],res[MAXN],pre[MAXN]; int key[MAXN],fa[MAXN]; ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } void newnode(int pos){ rt[pos]=1;size[pos]=1;minn[pos]=key[pos]=pos;ch[pos][0]=ch[pos][1]=0;res[pos]=0;pre[pos]=0;fa[pos]=pos; } int find1(int x){ if(x==fa[x])return x; else return fa[x]=find1(fa[x]); } void reverse(int r){ if(!r)return ; swap(ch[r][0],ch[r][1]); res[r]^=1; } void push(int x){ if(res[x]){ reverse(ch[x][0]); reverse(ch[x][1]); res[x]=0; } } void up(int x){ minn[x]=min(minn[ch[x][0]],minn[ch[x][1]]); minn[x]=min(minn[x],key[x]); size[x]=size[ch[x][0]]+size[ch[x][1]]+1; } void P(int x){ if(!rt[x])P(find1(pre[x])); push(x); } void rotate(int x,int kind){ int y=find1(pre[x]); ch[y][!kind]=ch[x][kind];pre[ch[x][kind]]=y; if(rt[y])rt[x]=1,rt[y]=0; else ch[find1(pre[y])][ch[find1(pre[y])][1]==y]=x; pre[x]=find1(pre[y]);ch[x][kind]=y;pre[y]=x;up(y); } void splay(int x){ P(x); while(!rt[x]){ if(rt[find1(pre[x])])rotate(x,ch[find1(pre[x])][0]==x); else{ int y=find1(pre[x]);int kind=ch[find1(pre[y])][0]==y; if(ch[y][kind]==x)rotate(x,!kind),rotate(x,kind); else rotate(y,kind),rotate(x,kind); } } up(x); } void access(int x){ int y=0;//cout<<x<<"-----===="<<endl; while(x){ splay(x); if(ch[x][1])pre[ch[x][1]]=x,rt[ch[x][1]]=1,ch[x][1]=0; if(rt[y])rt[y]=0; ch[x][1]=y;up(x); y=x;x=find1(pre[x]); } } void mroot(int x){ access(x);splay(x);reverse(x); } bool pd(int u,int v){ while(pre[u])u=find1(pre[u]); while(pre[v])v=find1(pre[v]); return u==v; } void Link(int u,int v){ mroot(u);mroot(v);pre[u]=v; } vector<int>vec; void dfs(int v){ if(!v)return ; vec.push_back(v); dfs(ch[v][0]); dfs(ch[v][1]); } void destory(int u,int v){ mroot(u);access(v);splay(v); // cout<<u<<" "<<v<<endl; // cout<<"sb"<<endl; int tx=minn[v]; // cout<<tx<<endl; dfs(v); // cout<<tx<<endl; for(int i=0;i<vec.size();i++)fa[vec[i]]=tx,ch[vec[i]][0]=ch[vec[i]][1]=0,rt[vec[i]]=1; // cout<<endl; //cout<<tx<<endl; for(int i=0;i<vec.size();i++)pre[vec[i]]=0; vec.clear(); up(tx); } void slove(int u,int v){ u=find1(u);v=find1(v); // cout<<pd(u,v)<<endl; if(pd(u,v)) destory(u,v); else Link(u,v); } int querty(int u,int v){ u=find1(u);v=find1(v); //cout<<u<<" "<<v<<endl; mroot(u);access(v); // cout<<"sb"<<endl; splay(v); return size[v]-1; } typedef struct node{ int op,u,v; }node; node que[NM]; set<pair<int,int> >s; set<pair<int,int> >::iterator ite; stack<int>ss; int main(){ minn[0]=1e9+7; int n,m;n=read();m=read(); for(int i=1;i<=n;i++)newnode(i); int u,v,op; for(int i=1;i<=m;i++){u=read(),v=read(); if(u>v)swap(u,v); s.insert(make_pair(u,v));} int cnt=0; while(scanf("%d",&op)!=EOF){ if(op==-1)break; que[++cnt].op=op;que[cnt].u=read();que[cnt].v=read(); if(que[cnt].op==1)continue; // cout<<cnt<<endl; // cout<<que[cnt].op<<" "<<que[cnt].u<<" "<<que[cnt].v<<endl; if(que[cnt].u>que[cnt].v)swap(que[cnt].u,que[cnt].v); s.erase(s.find(make_pair(que[cnt].u,que[cnt].v))); } // cout<<cnt<<endl; for(ite=s.begin();ite!=s.end();ite++){ slove(ite->first,ite->second); } // cout<<"sb"<<endl; // cout<<minn[1]<<endl; for(int i=cnt;i>=1;i--){ if(que[i].op==1){ ss.push(querty(que[i].u,que[i].v)); // cout<<"sb"<<endl; } else slove(que[i].u,que[i].v); } // cout<<"sb"<<endl; while(!ss.empty()){ printf("%d\n",ss.top()); ss.pop(); } return 0; }
1969: [Ahoi2005]LANE 航线规划
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 637 Solved: 287
[Submit][Status][Discuss]
Description
对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系。
星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1、2、3……。
一些先遣飞船已经出发,在星球之间开辟探险航线。
探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线。
例如下图所示:
在5个星球之间,有5条探险航线。
A、B两星球之间,如果某条航线不存在,就无法从A星球抵达B星球,我们则称这条航线为关键航线。
显然上图中,1号与5号星球之间的关键航线有1条:即为4-5航线。
然而,在宇宙中一些未知的磁暴和行星的冲撞,使得已有的某些航线被破坏,随着越来越多的航线被破坏,探险飞船又不能及时回复这些航线,可见两个星球之间的关键航线会越来越多。
假设在上图中,航线4-2(从4号星球到2号星球)被破坏。此时,1号与5号星球之间的关键航线就有3条:1-3,3-4,4-5。
小联的任务是,不断关注航线被破坏的情况,并随时给出两个星球之间的关键航线数目。现在请你帮助完成。
Input
第一行有两个整数N,M。表示有N个星球(1< N
< 30000),初始时已经有M条航线(1 < M <
100000)。随后有M行,每行有两个不相同的整数A、B表示在星球A与B之间存在一条航线。接下来每行有三个整数C、A、B。C为1表示询问当前星球A和星球B之间有多少条关键航线;C为0表示在星球A和星球B之间的航线被破坏,当后面再遇到C为1的情况时,表示询问航线被破坏后,关键路径的情况,且航线破坏后不可恢复;
C为-1表示输入文件结束,这时该行没有A,B的值。被破坏的航线数目与询问的次数总和不超过40000。
Output
对每个C为1的询问,输出一行一个整数表示关键航线数目。
注意:我们保证无论航线如何被破坏,任意时刻任意两个星球都能够相互到达。在整个数据中,任意两个星球之间最多只可能存在一条直接的航线。
Sample Input
5 5
1 2
1 3
3 4
4 5
4 2
1 1 5
0 4 2
1 5 1
-1
1 2
1 3
3 4
4 5
4 2
1 1 5
0 4 2
1 5 1
-1
Sample Output
1
3