树剖维护边双

首先我们看到在整个过程中图是保证连通的,于是我们并不需要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. Golang教程:变量

    声明单一变量 声明一个变量的语法为:var name type,例如 package main import "fmt" func main() { var age int // ...

  2. OOP 第一章作业总结

    程序设计结构分析 类图分析 第一次作业 由于第一次作业完成的功能比较简单,而且出于对面向对象设计理念不熟悉(其实现在也不是很熟悉,逃),整个程序设计的非常简单.通过类图(见下)可以看出,程序只有两个类 ...

  3. docker 安装ElasticSearch head

    github官网地址 https://github.com/mobz/elasticsearch-head 拉取镜像 docker pull mobz/elasticsearch-head:5 创建容 ...

  4. Error:Execution failed for task ':xutils:mergeDebugAndroidTestResources'. > No slave process to proc

    Error:Execution failed for task ':xutils:mergeDebugAndroidTestResources'. > No slave process to p ...

  5. 比较全的css重设

    一.最简化的CSS Reset(重设) : * { padding:; margin:; } 这是最普遍最简单的CSS重设,将所有元素的padding和margin值都设为0,可以避免一些浏览器在理解 ...

  6. 11.1NOIP模拟赛解题报告

    心路历程 预计得分:\(100 + 100 + 50\) 实际得分:\(100 + 100 + 50\) 感觉老师找的题有点水呀. 上来看T1,woc?裸的等比数列求和?然而我不会公式呀..感觉要凉 ...

  7. XPath路径表达式笔记(转载)

    简单说,xpath就是选择XML文件中节点的方法. 所谓节点(node),就是XML文件的最小构成单位,一共分成7种. - element(元素节点)- attribute(属性节点)- text ( ...

  8. hdu 4513 吉哥系列故事——完美队形II (manachar算法)

    吉哥系列故事——完美队形II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) P ...

  9. 佣金百万so easy!阿里云推广联盟喊你来赚钱

    淘客速来,佣金百万so easy!阿里云推广联盟喊你来赚钱 阿里云CPS推广阶梯返佣活动火热升级! 坐享15%佣金!一笔成交即有奖励!最高奖励2000元! 超高客单价.高转化率.高佣金! 招募淘客推广 ...

  10. 花1台的钱入手2台【最能抗DDoS】阿里云主机【攻略】

    花1台的钱入手2台[最能抗DDoS]阿里云主机[攻略]: 第一步:先申请0元半年 http://click.aliyun.com/m/335/:注:0元机器只有新帐号可申请第二步:再买6折37/月 h ...