树剖维护边双

首先我们看到在整个过程中图是保证连通的,于是我们并不需要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. Firebird 用查询结果集更新数据,merge

    Merge语法: MERGE INTO target [[AS] target-alias ] USING source [[AS] source-alias ] ON join-condition ...

  2. 图像的点运算----底层代码与Halcon库函数

    最基本的图像分析工具----灰度直方图.使用直方图辅助,可以实现4大灰度变换,包括线性灰度变换(灰度拉伸).灰度对数变换.灰度伽马变换.灰度分段线性变换:使用直方图修正技术,可以实现2大变换,包括直方 ...

  3. SQL2008使用with求余额表,流水账方式

    1.先准备数据,将要求余额的表数据插入临时表 SELECT Serial, VoucherNum, SubjectNum, SubjectName, Direction, Amount INTO #T ...

  4. laravel后台注册登入

    1.只需要在新安装的 Laravel 应用下运行 php artisan make:auth 和 php artisan migrate,这两个命令会生成用户登录注册所需要的所有东西 2.你会发现 h ...

  5. 动画演示10个有趣但毫无用处的Linux命令

    Linux最强大的一个特征就是它有大量的各种小命令工具,这也可以称做是它最有趣的一个地方了.在这些大量的有用的命令和脚本中,你会发现有少部 分命令工具不那么有用的——如果你不愿意说是完全没用处的话.你 ...

  6. 【阿里云产品公测】ACE下上传文件永久存储实践

    本帖主要内容: ;$,=VB:'   在阿里云的ACE下,我是如何实现让上传的文件永久保存的? ,%"!8T   本文以PHP为例,具体知识点如下: WD# 96V   第一,扩展服务“存储 ...

  7. MSSQLServer——全国省份城市SQL语句

    use hr create table dbo.province ( proID int primary key, proName ), keys ) ) ,'北京市','B'); ,'天津市','T ...

  8. Android 高速录像(2)

    private void startRecordVideo() { if (index == VIDEO_1080) { if (!supported1080P120Fps) { showToast( ...

  9. PHP discuz模板语法

    Discuz! X 模板的解析主要是 ./source/class/class_template.php 文件解析处理的,如果需要深入了解请可以看看这个文件! 模板嵌套语法 将被嵌套模板内容解析为 P ...

  10. 10.符号链接&创建链接

    在我们到处查看时,我们可能会看到一个目录,列出像这样的一条信息: lrwxrwxrwx 1 root root 11 2007-08-11 07:34 libc.so.6 -> libc-2.6 ...