题目描述

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

输入

第一行有两个整数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。

输出

对每个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

首先,题意是求动态图的两点桥数。

将边删除会很麻烦,所以先将要删去的边去掉,形成最后的图。

求边双联通分量,缩点,形成一棵树(一定是一棵树)树边为关键边。

再根据数据加边,每加入一边,则形成一个环,则环上路不再为关键边,最后将答案逆序输出。

加入边后,两点之间的路径中的关键边可用树剖和线段树维护。

线段树中,1表是关键边,0表不是,维护和。每加入一边,求两点LCA,并将线段树相应区间归零(要做延迟表记)。查询就输出线段树相应区间的和

注意细节,代码有点长

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
using namespace std;
struct Messi1
{
int next,to;
}edge1[],edge2[];
struct Messi2
{
int p,q,c;
}a[],b[];
int isbridge[],son[],size[],fa[],dep[],top[],pos[],tot,m;
int head1[],head2[],num1,num2,dfn[],low[],dfscnt,sccno[],n,scccnt,ans[];
int lazy[],c[],cx;
typedef pair<int,int> dou;//定义数对
set<dou> vis,vis2;//此处用set可节约内存,且方便。
void add1(int u,int v)//原图
{
num1++;
edge1[num1].next=head1[u];
edge1[num1].to=v;
head1[u]=num1;
}
void add2(int u,int v)//缩点后的图
{
num2++;
edge2[num2].next=head2[u];
edge2[num2].to=v;
head2[u]=num2;
}
void tarjan(int x,int fa)
{int i;
dfn[x]=low[x]=++dfscnt;
int child=;
for (i=head1[x]; i; i=edge1[i].next)
{
int v=edge1[i].to;
if (dfn[v]==)
{
child++;
tarjan(v,x);
low[x]=min(low[x],low[v]);
if (dfn[x]<low[v]) isbridge[i]=;
}
else if (v!=fa) low[x]=min(low[x],dfn[v]);
}
}
void dfs(int x,int v)
{int i;
//cout<<x<<' '<<v<<endl;
dfn[x]=;
sccno[x]=v;
for (i=head1[x]; i; i=edge1[i].next)
if (isbridge[i]==&&dfn[edge1[i].to]==)
{
dfs(edge1[i].to,v);
}
}
void make_tree()
{int i,j,x1,y1;
tarjan(,-);
memset(dfn,,sizeof(dfn));
for (i=; i<=n; i++)
if (dfn[i]==)
{
scccnt++;
dfs(i,scccnt);
}
for (i=; i<=n; i++)
{
for (j=head1[i]; j; j=edge1[j].next)
{
int v=edge1[j].to;
if (sccno[i]!=sccno[v])
{if (sccno[i]>sccno[v]) x1=sccno[v],y1=sccno[i];
else y1=sccno[v],x1=sccno[i];
if (vis2.find(make_pair(x1,y1))==vis2.end())
//注:set的find函数返回指针,不存在时反回最后节点子节点,
所以不能写!find()。用end函数反回最后节点子节点
{
add2(x1,y1);
add2(y1,x1);
vis2.insert(make_pair(x1,y1));
}
}
}
}
}
void dfs1(int u,int pa,int depth)
{
son[u]=;
size[u]=;
fa[u]=pa;
dep[u]=depth;
for (int j=head2[u]; j; j=edge2[j].next)
{
int v=edge2[j].to;
if (v!=pa)
{
dfs1(v,u,depth+);
size[u]+=size[v];
if (size[v]>size[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
pos[u]=++tot;
if (son[u]) dfs2(son[u],tp);
for (int j=head2[u]; j; j=edge2[j].next)
if (edge2[j].to!=son[u]&&edge2[j].to!=fa[u])
{
dfs2(edge2[j].to,edge2[j].to);
}
}
void pushdown(int rt)
{
if (lazy[rt])
{
c[rt*]=;
lazy[rt*]=;
c[rt*+]=;
lazy[rt*+]=;
lazy[rt]=;
}
}
int ask(int rt,int l,int r,int L,int R)
{
if (l!=r) pushdown(rt);
if (l>=L&&r<=R)
{
return c[rt];
}
pushdown(rt);
int mid=(l+r)/,s=;
if (L<=mid) s+=ask(rt*,l,mid,L,R);
if (R>mid) s+=ask(rt*+,mid+,r,L,R);
return s;
}
int query(int x,int y)
{
int s=;
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
s+=ask(,,n,pos[top[x]],pos[x]);
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
if (x!=y) s+=ask(,,n,pos[x]+,pos[y]);
return s;
}
void update(int rt,int l,int r,int L,int R)
{
if (l!=r)pushdown(rt);
if (l>=L&&r<=R)
{
c[rt]=;
lazy[rt]=;
return;
}
pushdown(rt);
int mid=(l+r)/;
if (L<=mid) update(rt*,l,mid,L,R);
if (R>mid) update(rt*+,mid+,r,L,R);
c[rt]=c[rt*]+c[rt*+];
}
void change(int x,int y)
{
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
update(,,n,pos[top[x]],pos[x]);
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
if (x!=y) update(,,n,pos[x]+,pos[y]);
}
void build(int rt,int l,int r)
{
if (l==r)
{
c[rt]=;
return;
}
int mid=(l+r)/;
build(rt*,l,mid);
build(rt*+,mid+,r);
c[rt]=c[rt*]+c[rt*+];
}
int main()
{int i,j,x,y;
//freopen("lane.in","r",stdin);
//freopen("lane.out","w",stdout);
cin>>n>>m;
for (i=; i<=m; i++)
{
scanf("%d%d",&a[i].p,&a[i].q);
vis.insert(make_pair(a[i].p,a[i].q));
}
int tot1=;
scanf("%d",&cx);
while (cx!=-)
{
scanf("%d%d",&x,&y);
if (cx==)
{
tot1++;
b[tot1].p=x;
b[tot1].q=y;
b[tot1].c=;
vis.erase(make_pair(x,y));
}
else
{
tot1++;
b[tot1].c=;
b[tot1].p=x;
b[tot1].q=y;
}
scanf("%d",&cx);
}
for (i=; i<=m; i++)
{
if (vis.find(make_pair(a[i].p,a[i].q))!=vis.end())
{
add1(a[i].p,a[i].q);
add1(a[i].q,a[i].p);
}
}
make_tree();
dfs1(,,);
dfs2(,);
n=scccnt;
//cout<<scccnt<<endl;
build(,,n);
memset(ans,-,sizeof(ans));
for (i=tot1; i>=; i--)
{
if (b[i].c==)
{
int u=sccno[b[i].p],v=sccno[b[i].q];
change(u,v);
}
else
{
int u=sccno[b[i].p],v=sccno[b[i].q];
ans[i]=query(u,v);
}
}
for (i=; i<=tot1; i++)
if (ans[i]!=-) printf("%d\n",ans[i]);
}

[Ahoi2005]LANE 航线规划的更多相关文章

  1. BZOJ 1969: [Ahoi2005]LANE 航线规划( 树链剖分 )

    首先我们要时光倒流, 倒着做, 变成加边操作维护关键边. 先随意搞出一颗树, 树上每条边都是关键边(因为是树, 去掉就不连通了)....然后加边(u, v)时, 路径(u, v)上的所有边都变成非关键 ...

  2. 【BZOJ 1969】 1969: [Ahoi2005]LANE 航线规划 (树链剖分+线段树)

    1969: [Ahoi2005]LANE 航线规划 Description 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星 ...

  3. 【BZOJ1969】[Ahoi2005]LANE 航线规划 离线+树链剖分+线段树

    [BZOJ1969][Ahoi2005]LANE 航线规划 Description 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由 ...

  4. BZOJ1969: [Ahoi2005]LANE 航线规划(LCT)

    Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 587  Solved: 259[Submit][Status][Discuss] Description ...

  5. 【刷题】BZOJ 1969 [Ahoi2005]LANE 航线规划

    Description 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系--一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel ...

  6. 【bzoj1959】[Ahoi2005]LANE 航线规划 树链剖分+线段树

    题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...

  7. [bzoj1969] [Ahoi2005]LANE 航线规划

    tarjan.并查集.树状数组.树链剖分. 时间倒流,变删边为加边. 先求一波边双联通分量,缩点. 题目保证最后还是整张图联通的..所以就是一棵树. 现在的操作就是,将路径上的边权置0(加边时),查询 ...

  8. BZOJ 1969: [Ahoi2005]LANE 航线规划 [树链剖分 时间倒流]

    题意: 一张图,删除边,求两点之间的割边数量.保证任意时刻图连通 任求一棵生成树,只有树边可能是割边 时间倒流,加入一条边,就是两点路径上的边都不可能是割边,区间覆盖... 然后本题需要把边哈希一下, ...

  9. ●BZOJ 1969 [Ahoi2005]LANE 航线规划

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1969 题解: 线段树,树链剖分,反向考虑思路是很巧妙,但是感觉代码真的恶心.. 反着考虑,先 ...

随机推荐

  1. Beta阶段敏捷冲刺报告-DAY5

    Beta阶段敏捷冲刺报告-DAY5 Scrum Meeting 敏捷开发日期 2017.11.6 会议时间 12:00 会议地点 软工所 参会人员 全体成员 会议内容 乱序问题的解决,异常输入提示 讨 ...

  2. python3.* socket例子

    On Server: # -*- coding: utf-8 -*-#this is the server import socketif "__main__" == __name ...

  3. 解决background图片拉伸问题

    ImageView中XML属性src和background的区别: background会根据ImageView组件给定的长宽进行拉伸,而src就存放的是原图的大小,不会进行拉伸.src是图片内容(前 ...

  4. JAVA线程池原理详解(1)

    线程池的优点 1.线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用. 2.可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃. 线 ...

  5. 前端面试题之html

    1.简述<!DOCTYPE> 的作用,标准模式和兼容模式各有什么区别? <!DOCTYPE> 位于文档的第一行,告知浏览器使用哪种规范. 如果不写DOCTYPE,浏览器会进入混 ...

  6. 在wamp集成环境下安装laravel5.2.*框架

    虽然官方一直强烈推荐使用homestead,但是这个相对麻烦一点,所以我还是选择使用wamp集成开发环境.还有这里我只讲解windows系统下的安装,其他例如mac或linux就不写了,此文章是面向刚 ...

  7. JQ 上传文件(单个,多个,分片)

    最原始的方式: 前端代码: <div> <span>最原始的方式</span><br /> <span>条件1:必须是 post 方式< ...

  8. [机器学习Lesson3] 梯度下降算法

    1. Gradient Descent(梯度下降) 梯度下降算法是很常用的算法,可以将代价函数J最小化.它不仅被用在线性回归上,也被广泛应用于机器学习领域中的众多领域. 1.1 线性回归问题应用 我们 ...

  9. python网络编程基础(一)

    一.C/S架构 客户端/服务端架构 二.OSI七层架构 七层模型,亦称OSI(Open System Interconnection)参考模型,是参考模型是国际标准化组织(ISO)制定的一个用于计算机 ...

  10. 初试valgrind内存调试工具

    虽然GDB调试工具功能强大,但对于平时做题调试的使用并不方便,这里尝试学习使用比较简单的valgrind工具 Valgrind是一个提供程序调试及性能分析的工具集.其包含的工具主要有Memcheck, ...