【AHOI2005】【BZOJ1969】LANE 航线规划

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

HINT

Source

还是国内比赛数据良心..我自己的code飞快的就A了..
把PA那题的pushup里的|运算改成+,再改改读入就没了..

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#define MAXN 200010
#define GET (ch>='0'&&ch<='9')
using namespace std;
int n,m,Q;
void in(int &x)
{
    char ch=getchar();x=0;int flag=1;
    while (!GET)    flag=ch=='-'?-1:1,ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();x*=flag;
}
int sta[MAXN],top;
int f[MAXN];
map<int,bool> del[MAXN>>1];
int find(int x) {   return f[x]==x?x:f[x]=find(f[x]);   }
struct edge
{   
    int u,v,id;
    bool operator <(const edge& a)const  {   return u==a.u?v<a.v:u<a.u;    }
}e[MAXN];
struct Query    {   int opt,u,v,ans;    }q[MAXN];
struct Splay
{
    int ch[2],fa,sum,val;
    bool rev,flag;
}tree[MAXN];
inline bool is_root(int x)  {   return tree[tree[x].fa].ch[0]!=x&&tree[tree[x].fa].ch[1]!=x;    }
inline void push_up(int x)  {   tree[x].sum=tree[x].val+tree[tree[x].ch[0]].sum+tree[tree[x].ch[1]].sum;    }
inline void push_down(int x)
{
    if (!x) return;
    int l=tree[x].ch[0],r=tree[x].ch[1];
    if (tree[x].flag)
    {
        tree[l].sum=tree[l].val=0;tree[r].sum=tree[r].val=0;
        tree[l].flag=1;tree[r].flag=1;tree[x].flag=0;
    }
    if (tree[x].rev)
    {
        tree[l].rev^=1;tree[r].rev^=1;
        swap(tree[x].ch[0],tree[x].ch[1]);tree[x].rev^=1;
    }
}
inline void rot(int x)
{
    int y=tree[x].fa,z=tree[y].fa,l=tree[y].ch[1]==x,r=l^1;
    if (!is_root(y))    tree[z].ch[tree[z].ch[1]==y]=x;
    tree[x].fa=z;tree[y].fa=x;tree[tree[x].ch[r]].fa=y;
    tree[y].ch[l]=tree[x].ch[r];tree[x].ch[r]=y;
    push_up(y);push_up(x);
}
inline void Splay(int x)
{
    top=0;sta[++top]=x;
    for (int i=x;!is_root(i);i=tree[i].fa)  sta[++top]=tree[i].fa;
    while (top) push_down(sta[top--]);
    while (!is_root(x))
    {
        int y=tree[x].fa,z=tree[y].fa;
        if (!is_root(y))
        {
            if ((tree[y].ch[0]==x)^(tree[z].ch[0]==x))  rot(x);
            else    rot(y);
        }
        rot(x);
    }
}
inline void access(int x)   {   for (int i=0;x;i=x,x=tree[x].fa)    Splay(x),tree[x].ch[1]=i,push_up(x);    }
inline void make_root(int x)    {   access(x);Splay(x);tree[x].rev^=1;  }
inline void link(int x,int y)   {   make_root(x);tree[x].fa=y;  }
inline void ins(int x,int y)
{
    int p=find(x),q=find(y);
    if (p!=q)
    {
        f[p]=q;n++;tree[n].sum=tree[n].val=1;
        link(x,n);link(y,n);
        return;
    }
    make_root(x);access(y);Splay(y);tree[y].sum=tree[y].val=0;tree[y].flag=1;
}
inline int query(int x,int y)
{
    int p=find(x),q=find(y);
    if (p!=q)   return 1;
    make_root(x);access(y);Splay(y);return tree[y].sum;
}
int main()
{
    in(n);in(m);int opt,u,v;
    for (int i=1;i<=n;i++)   f[i]=i;
    for (int i=1;i<=m;i++)
    {
        in(u);in(v);if (u>v) swap(u,v);
        e[i].u=u;e[i].v=v;e[i].id=i;
    }
    for (in(opt);opt!=-1;in(opt))
    {
        in(u);in(v);if (u>v)  swap(u,v);
        q[++Q].opt=opt;q[Q].u=u;q[Q].v=v;
        if (!opt) del[q[Q].u][q[Q].v]=1;
    }
    for (int i=1;i<=m;i++)
    {
        if (del[e[i].u][e[i].v])    continue;
        int p=find(e[i].u),q=find(e[i].v);
        if (p==q)   continue;
        f[p]=q;n++;tree[n].sum=tree[n].val=1;
        link(e[i].u,n);link(e[i].v,n);del[e[i].u][e[i].v]=1;
    }
    for (int i=1;i<=m;i++)   if (!del[e[i].u][e[i].v])   ins(e[i].u,e[i].v);
    for (int i=Q;i;i--)
        if (q[i].opt==0)    ins(q[i].u,q[i].v);
        else    q[i].ans=query(q[i].u,q[i].v);
    for (int i=1;i<=Q;i++)   if (q[i].opt)   printf("%d\n",q[i].ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值