树剖维护边双

首先我们看到在整个过程中图是保证连通的,于是我们并不需要LCT来维护连通性

而这些询问询问的是两个点之间关键路径的数量,也就是无论怎么走都必须走的数量,显然这就是两点之间的割边的数量

由于这里还有一些删除操作,树剖并不支持,所以我们先将所有的答案读进来,删掉所有的边

之后我们就\(Tarjan\)把边双缩出来,之后建一棵树就好了

之后我们倒着完成所有操作

对于询问操作,我们直接询问两点之间的距离就行了

对于删除操作,由于我们提前删除完了,所以我们现在需要把边恢复过来,于是我们如果要恢复\((u,v)\)这条边的话,如果\((u,v)\)在一个边双里,我们们不需要管这个操作,而如果不在那么树上\((u,v)\)两点对应边双之间就不会存在桥了,我们直接用树剖将这些边权搞成0就好了

超级长的代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#define re register
#define maxn 30005
struct node
{
int v,nxt;
}e[maxn<<3];
int head[maxn],to[maxn],top[maxn],fa[maxn],deep[maxn],sum[maxn],son[maxn];
int a[maxn],b[maxn],belong[maxn];
int opt[maxn<<1],xx[maxn<<1],yy[maxn<<1];
int l[maxn<<2],r[maxn<<2],d[maxn<<2],tag[2][maxn<<2],t[maxn<<2];
int n,m,k,Q,p,num=0;
int tot,now;
inline int read()
{
char c=getchar();
int x=0,r=1;
while(c<'0'||c>'9'){if(c=='-') r=-1;c=getchar();}
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x*r;
}
inline void add_edge(int x,int y)
{
e[++num].v=y;
e[num].nxt=head[x];
head[x]=num;
}
void dfs1(int r)
{
sum[r]=1;
int maxx=-1;
for(re int i=head[r];i;i=e[i].nxt)
if(!deep[e[i].v])
{
deep[e[i].v]=deep[r]+1;
fa[e[i].v]=r;
dfs1(e[i].v);
sum[r]+=sum[e[i].v];
if(sum[e[i].v]>maxx) maxx=sum[e[i].v],son[r]=e[i].v;
}
}
void dfs2(int r,int topf)
{
top[r]=topf;
to[r]=++k;
b[k]=r;
if(!son[r]) return;
dfs2(son[r],topf);
for(re int i=head[r];i;i=e[i].nxt)
if(deep[e[i].v]>deep[r]&&son[r]!=e[i].v) dfs2(e[i].v,e[i].v);
}
void build(int x,int y,int i)
{
l[i]=x;
r[i]=y;
tag[0][i]=tag[1][i]=-1;
if(x==y)
{
t[i]=b[x];
d[i]=1;
return;
}
int mid=x+y>>1;
build(x,mid,i<<1);
build(mid+1,y,i<<1|1);
d[i]=d[i<<1]+d[i<<1|1];
}
inline void pushdown(int i)
{
if(tag[0][i]!=-1&&tag[1][i]!=-1)
{
tag[0][i<<1]=0;
tag[0][i<<1|1]=0;
d[i<<1]=0;
d[i<<1|1]=0;
t[i<<1]=tag[1][i<<1]=tag[1][i];
t[i<<1|1]=tag[1][i<<1|1]=tag[1][i];
tag[0][i]=-1;
tag[1][i]=-1;
}
}
void change(int x,int y,int v1,int v2,int i)
{
if(x<=l[i]&&y>=r[i])
{
d[i]=v1;
t[i]=v2;
tag[0][i]=v1;
tag[1][i]=v2;
return;
}
pushdown(i);
int mid=l[i]+r[i]>>1;
if(y<=mid) change(x,y,v1,v2,i<<1);
else if(x>mid) change(x,y,v1,v2,i<<1|1);
else change(x,y,v1,v2,i<<1),change(x,y,v1,v2,i<<1|1);
d[i]=d[i<<1]+d[i<<1|1];
}
int query(int x,int y,int i)
{
if(x<=l[i]&&y>=r[i]) return d[i];
pushdown(i);
int mid=l[i]+r[i]>>1;
if(y<=mid) return query(x,y,i<<1);
if(x>mid) return query(x,y,i<<1|1);
return query(x,y,i<<1|1)+query(x,y,i<<1);
}
int ask(int x,int i)
{
if(l[i]==r[i]) return t[i];
pushdown(i);
int mid=l[i]+r[i]>>1;
if(x<=mid) return ask(x,i<<1);
return ask(x,i<<1|1);
}
inline int tree_query(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) std::swap(x,y);
ans+=query(to[top[x]],to[x],1);
x=fa[top[x]];
}
if(x==y) return ans;
if(deep[x]>deep[y]) std::swap(x,y);
ans+=query(to[x]+1,to[y],1);
return ans;
}
inline void tree_change(int x,int y,int k)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) std::swap(x,y);
change(to[top[x]],to[x],0,k,1);
x=fa[top[x]];
}
if(x==y) return;
if(deep[x]>deep[y]) std::swap(x,y);
change(to[x]+1,to[y],0,k,1);
}
namespace Tarjan
{
int dfn[maxn],low[maxn],st[maxn];
std::set< std::pair<int,int> > s;
int head[maxn];
struct EDGE
{
int v,nxt;
}e[maxn<<3],E[maxn<<3];
int num=0,cnt,mid,top;
inline void add(int x,int y)
{
e[++num].v=y;
e[num].nxt=head[x];
head[x]=num;
}
void tarjan(int x,int fa)
{
st[++top]=x;
dfn[x]=low[x]=++cnt;
for(re int i=head[x];i;i=e[i].nxt)
if(!dfn[e[i].v]) tarjan(e[i].v,x),low[x]=std::min(low[x],low[e[i].v]);
else if(e[i].v!=fa) low[x]=std::min(low[x],dfn[e[i].v]);
if(low[x]==dfn[x])
{
p++;
do
{
mid=st[top--];
belong[mid]=p;
}while(x!=mid);
}
}
void prepare()
{
n=read();
m=read();
for(re int i=1;i<=m;i++)
E[i].v=read(),E[i].nxt=read();
int x,y;
while(1)
{
opt[Q+1]=read();
if(opt[Q+1]==-1) break;
if(opt[Q+1]==1) tot++;
Q++;
xx[Q]=read();
yy[Q]=read();
if(!opt[Q])
{
s.insert(std::make_pair(xx[Q],yy[Q]));
s.insert(std::make_pair(yy[Q],xx[Q]));
}
}
for(re int i=1;i<=m;i++)
if(s.find(std::make_pair(E[i].v,E[i].nxt))==s.end()&&s.find(std::make_pair(E[i].nxt,E[i].v))==s.end())
add(E[i].v,E[i].nxt),add(E[i].nxt,E[i].v);
tarjan(1,0);
for(re int i=1;i<=n;i++)
for(re int j=head[i];j;j=e[j].nxt)
if(belong[i]!=belong[e[j].v]) add_edge(belong[i],belong[e[j].v]);
}
}
int main()
{
Tarjan::prepare();
deep[1]=1;
dfs1(1);
now=tot;
dfs2(1,1);
build(1,p,1);
change(1,1,0,b[1],1);
for(re int T=Q;T;T--)
{
if(opt[T]==1) a[now--]=tree_query(belong[xx[T]],belong[yy[T]]);
else
{
if(ask(to[belong[xx[T]]],1)==ask(to[belong[yy[T]]],1)) continue;
tree_change(belong[xx[T]],belong[yy[T]],++p);
}
}
for(re int i=1;i<=tot;i++)
printf("%d\n",a[i]);
return 0;
}

【[AHOI2005]航线规划】的更多相关文章

  1. 洛谷 P2542 [AHOI2005]航线规划 解题报告

    P2542 [AHOI2005]航线规划 题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系--一个巨大的由千百万星球构成的Samuel星系 ...

  2. P2542 【[AHOI2005]航线规划】

    P2542 [[AHOI2005]航线规划] 一个无向图,m个操作 删去一条边 给定两个点,求有多少边使得如果这条边不存在,给定的两个点不连通 一般这种删边的题目,考虑逆序加边处理 在删完的图中,任意 ...

  3. [AHOI2005] 航线规划

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

  4. AHOI2005航线规划 bzoj1969(LCT缩点)

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

  5. P2542 [AHOI2005]航线规划 LCT维护双连通分量

    \(\color{#0066ff}{ 题目描述 }\) 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系--一个巨大的由千百万星球构成的Samuel ...

  6. 洛谷P2542 [AHOI2005]航线规划(LCT,双连通分量,并查集)

    洛谷题目传送门 太弱了不会树剖,觉得LCT好写一些,就上LCT乱搞,当LCT维护双连通分量的练手题好了 正序删边是不好来维护连通性的,于是就像水管局长那样离线处理,逆序完成操作 显然,每个点可以代表一 ...

  7. 洛谷 P2542 [AHOI2005]航线规划(Link-cut-tree)

    题面 洛谷 bzoj 题解 离线处理+LCT 有点像星球大战 我们可以倒着做,断边变成连边 我们可以把边变成一个点 连边时,如果两个点本身不联通,就\(val\)赋为\(1\),并连接这条边 如果,两 ...

  8. [AHOI2005]航线规划——LCT维护边双联通分量

    因为只能支持加入一个边维护边双,所以时光倒流 维护好边双,每次就是提取出(x,y)的链,答案就是链长度-1 具体维护边双的话, void access(int x){ for(reg y=0;x;y= ...

  9. 洛谷 P2542 [AHOI2005]航线规划 树链剖分_线段树_时光倒流_离线

    Code: #include <map> #include <cstdio> #include <algorithm> #include <cstring&g ...

随机推荐

  1. 【vm安装vmtools】

    使用sudo ./安装命令 对vmware-tools-distrib文件夹里面vmware-install.pl文件夹进行安装 sudo ./vmware-install.pl

  2. [转]Consuming a OData Service in a Client Application (WCF Data Services)

    本文转自:https://msdn.microsoft.com/zh-tw/library/dd728282(v=vs.103).aspx WCF Data Services 5.0   其他版本   ...

  3. C#基础笔记 转自wojiushigelg

    笔记如下: 概念:.net与c# .net/dontnet:一般指.net framework框架,一种平台,一种技术 c#(charp):一种编程语言,可以开发基于.net的应用. *java既是一 ...

  4. 数据结构(二) --- 伸展树(Splay Tree)

    文章图片和代码来自邓俊辉老师课件 概述 伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由丹尼尔·斯立特Daniel Sleator ...

  5. mybatis动态参数(使用PreparedStatement插入#)和静态参数($)

    1.使用#传递参数 #{}:被JDBC解析为PreparedStatement预编译语句,变量内容被当做一个整体变量,比如字符串,整形等. 2.使用$传递参数 ${}:纯粹是字符串替换,中间可以出现S ...

  6. SSH,SSM框架文件上传

    一.了解文件上传 1.1        什么是文件上传 将本地文件通过流的形式写到服务器上 1.2        文件上传的技术 JspSmartUpload: 其组件是应用jsp进行B/S程序开发过 ...

  7. GC回收策略

    判读一个对象是否“已死”: 引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器为0的对象就是不可能再被使用的. 至少主流的J ...

  8. 一台电脑上运行两个tomcat

    1.建立两个文件夹,tomcat1,tomcat2,分别在里面放入tomcat7文件(非安装版) 2.改配置 tomcat1中的配置就不用改了,直接用默认配置 tomcat2中的配置要改要,改conf ...

  9. JS 面向对象之继承---多种组合继承

    1. 组合继承:又叫伪经典继承,是指将原型链和借用构造函数技术组合在一块的一种继承方式. 下面来看一个例子: function SuperType(name) { this.name = name; ...

  10. 排序算法lowb三人组-冒泡排序

    冒泡排序:顾名思义就是像气泡从水里浮出来一样 把列表立起来如上图所示,从列表的第0项开始循环(把最大的数想成此次循环的气泡) 要把最大的放到上面那那就用第0项开始一次和剩下的开始比较,只要比第0项小就 ...