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 MB
Submit: 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

Sample Output

1
3

posted @ 2018-08-07 20:09  wang9897  阅读(142)  评论(0编辑  收藏  举报