[2018.07.26 T1] 航线规划

暂无链接

航线规划

【问题描述】

对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel
星球所在的星系——一个巨大的由千百万星球构成的Samuel星系。 星际空间站的Samuel
II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些
星球从1开始编号1、2、3……。 一些先遣飞船已经出发,在星球之间开辟探险航线。
探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星
球也可以使用这条航线。
例如下图所示:

无标题.png

在5个星球之间,有5条探险航线。 A、B两星球之间,如果某条航线不存在,就无法从A星球抵达B星球,我们则称这条航线为关键航线。 显然上图中,1号与5号星球之间的关键航线有1条:即为4-5航线。 然而,在宇宙中一些未知的磁暴和行星的冲撞,使得已有的某些航线被破坏,随着越来越多的航线被破坏,探险飞船又不能及时回复这些航线,可见两个星球之间的关键航线会越来越多。 假设在上图中,航线4-2(从4号星球到2号星球)被破坏。此时,1号与5号星球之间的关键航线就有3条:1-3,3-4,4-5。

小联的任务是,不断关注航线被破坏的情况,并随时给出两个星球之间的关键航线数目。现在请你帮助完成。

【输入格式】

第一行有两个整数N,M。表示有N个星球,初始时已经有M条航线。随后有M行,每行有两个不相同的整数A、B表示在星球A与B之间存在一条航线。接下来每行有三个整数C、A、B。C为1表示询问当前星球A和星球B之间有多少条关键航线;C为0表示在星球A和星球B之间的航线被破坏,当后面再遇到C为1的情况时,表示询问航线被破坏后,关键路径的情况,且航线破坏后不可恢复; C为-1表示输入文件结束,这时该行没有A,B的值。

【输出格式】

对每个C为1的询问,输出一行一个整数表示关键航线数目。 注意:我们保证无论
航线如何被破坏,任意时刻任意两个星球都能够相互到达。在整个数据中,任意两个星球
之间最多只可能存在一条直接的航线。

【输入样例】

5 5
1 2
1 3
3 4
4 5
4 2
1 1 5
0 4 2
1 5 1
-1

【输出样例】

1
3

【数据范围】

对于30%的数据:1 ≤ N ≤ 20,1 ≤ M ≤ 35,1 ≤ 查询次数+破坏航线数目 ≤ 100

对于50%的数据:1 ≤ N ≤ 5000,1 ≤ M ≤ 5300,1 ≤ 查询次数+破坏航线数目 ≤ 10000

对于100%的数据:1 ≤ N ≤ 30000,1 ≤ M ≤ 100000,1 ≤ 查询次数+破坏航线次数 ≤ 40000

题解

忘了拆点会让点数翻倍,少开了一半数组, 100 分惨变 60 分。

思路很简单,一看就需要离线,当图变成树的时候,所有边都是关键路径,倒着往里面加边的时候,每形成一个环,那么环上的所有路径都可以被这条路径在环上的补集替换,即整个环上的边都不再是关键路径了。

直接大力 L C T 维护,把边换成点权为 1 的点,成环的时候将整条链的点赋值为 0 L C T 维护一下点权和就可以求出链上的关键路径数了。

代码
#include<bits/stdc++.h>
#define ls son[v][0]
#define rs son[v][1]
using namespace std;
const int M=3e5+5;
struct sd{int op,a,b,id;}ope[M];
set<int>mmp[M];
int tot,n,m,id,son[M][2],dad[M],val[M],sum[M],ans[M];
bool rev[M],zero[M];
bool notroot(int v){return son[dad[v]][0]==v||son[dad[v]][1]==v;}
void up(int v){sum[v]=sum[ls]+sum[rs]+val[v];}
void turn(int v){swap(ls,rs),rev[v]^=1;}
void dan(int v){val[v]=sum[v]=0;zero[v]=1;}
void push(int v)
{
    if(rev[v]){if(ls)turn(ls);if(rs)turn(rs);rev[v]=0;}
    if(zero[v]){if(ls)dan(ls);if(rs)dan(rs);zero[v]=0;}
}
void down(int v){if(notroot(v))down(dad[v]);push(v);}
void spin(int v)
{
    int f=dad[v],ff=dad[f],k=son[f][1]==v,w=son[v][!k];
    if(notroot(f))son[ff][son[ff][1]==f]=v;son[v][!k]=f,son[f][k]=w;
    if(w)dad[w]=f;dad[f]=v,dad[v]=ff;
    up(f);up(v);
}
void splay(int v)
{
    down(v);int f,ff;
    while(notroot(v))
    {
        f=dad[v],ff=dad[f];
        if(notroot(f))spin((son[f][0]==v)^(son[ff][0]==f)?v:f);
        spin(v);
    }
    up(v);
}
void access(int v){for(int f=0;v;v=dad[f=v])splay(v),rs=f,up(v);}
void beroot(int v){access(v),splay(v),turn(v);}
int root(int v){access(v),splay(v);while(ls)push(v),v=ls;return v;}
void split(int x,int y){beroot(x),access(y),splay(y);}
void link(int x,int y){beroot(x);dad[x]=y;}
void in()
{
    int a,b,c;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d",&a,&b);
        if(a>b)swap(a,b);
        mmp[a].insert(b);
    }
    for(tot=1;;++tot)
    {
        scanf("%d",&a);if(a==-1)break;
        scanf("%d%d",&b,&c);
        if(!a)
        {
            if(b>c)swap(b,c);
            mmp[b].erase(c);
        }
        ope[tot]=(sd){a,b,c,tot};
    }
    --tot;
}
void ac()
{
    memset(ans,-1,sizeof(ans));
    set<int>::iterator j;id=n;
    for(int i=1;i<=n;++i)
    for(j=mmp[i].begin();j!=mmp[i].end();++j)
    {
        beroot(i);
        if(root(*j)!=i)
        {
            ++id;
            val[id]=sum[id]=1;
            link(i,id);link(id,*j);
        }
        else split(i,*j),dan(*j);
    }
    for(int i=tot;i>=1;--i)
    {
        if(ope[i].op)split(ope[i].a,ope[i].b),ans[ope[i].id]=sum[ope[i].b];
        else split(ope[i].a,ope[i].b),dan(ope[i].b);
    }
    for(int i=1;i<=tot;++i)if(~ans[i])printf("%d\n",ans[i]);
}
int main(){in();ac();}

猜你喜欢

转载自blog.csdn.net/shadypi/article/details/81222276
t1
今日推荐