题目大意:
给你一个无向连通图,再给出一些添边操作,询问每次添边操作之后图中还剩下多少桥。
思路:
考虑求出任意一棵生成树
若连接((u,v)),则生成树上u到v的路径上都不是桥
设一条边的边权为这条边是不是桥,是则为1,反之则为0
用树链剖分维护每一条边权,发现只能维护点权
WDNMD
考虑化边权为点权,设点(i)的权值为边((i,fa[i]))的权值
每一次修改把两个点的LCA特判一下,不要修改就行了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=100010;
const int M=200010;
inline void read(int &x) {
x=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9') {
if (ch=='-') {
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9') {
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
//*****MST部分*****//
struct note {
int t;
int next;
};
int cnt;
int head[N];
note e[M<<1];
struct edge {
int x;
int y;
};
int con;
edge E[M];
int f[N];
int vis[M];
int n,m,q;
inline void add(int x,int y) {
e[++cnt].t=y;
e[cnt].next=head[x];
head[x]=cnt;
}
int find(int x) {
return x==f[x]?x:f[x]=find(f[x]);
}
inline bool check(int x,int y) {
int fx=find(x),fy=find(y);
if (fx==fy) {
return 0;
} else {
f[fx]=f[y];
return 1;
}
}
inline void bulid_MST() {
for(int i=1;i<=n;i++) {
f[i]=i;
}
for(int i=1;i<=m;i++) {
if (check(E[i].x,E[i].y)) {
con++;
add(E[i].x,E[i].y);
add(E[i].y,E[i].x);
vis[i]=1;
}
if (con==n-1) {
break;
}
}
}
//------------------------//
//*****线段树部分*****//
struct seqt {
int ls;
int rs;
int val;
int f;
seqt() {
ls=rs=val=0;
f=-1;
}
};
seqt node[N<<2];
int siz;
int rt;
inline void update(int o) {
node[o].val=node[node[o].ls].val+node[node[o].rs].val;
}
inline void down(int o,int l,int r) {
int mid=(l+r)>>1;
node[node[o].ls].val=node[o].f*(mid-l+1);
node[node[o].rs].val=node[o].f*(r-mid);
node[node[o].ls].f=node[node[o].rs].f=node[o].f;
node[o].f=-1;
}
void build(int &o,int l,int r) {
o=++siz;
node[o].f=-1;
if (l==r) {
node[o].val=1;
return;
}
int mid=(l+r)>>1;
build(node[o].ls,l,mid);
build(node[o].rs,mid+1,r);
update(o);
}
void change(int o,int l,int r,int L,int R,int val) {
if (L<=l&&r<=R) {
node[o].val=val*(r-l+1);
node[o].f=val;
return;
}
if (node[o].f!=-1) {
down(o,l,r);
}
int mid=(l+r)>>1;
if (L<=mid) {
change(node[o].ls,l,mid,L,R,val);
}
if (mid<R) {
change(node[o].rs,mid+1,r,L,R,val);
}
update(o);
}
int query(int o,int l,int r,int L,int R) {
if (L<=l&&r<=R) {
return node[o].val;
}
if (node[o].f!=-1) {
down(o,l,r);
}
int mid=(l+r)>>1;
int ans=0;
if (L<=mid) {
ans+=query(node[o].ls,l,mid,L,R);
}
if (mid<R) {
ans+=query(node[o].rs,mid+1,r,L,R);
}
return ans;
}
//------------------------//
//*****树链剖分部分*****//
int tot;
int son[N],top[N],dep[N],fa[N],dfn[N],val[N];
void dfs1(int p,int fat) {
dep[p]=dep[fat]+1;
fa[p]=fat;
val[p]=1;
int max_son=-1;
for(int i=head[p];i+1;i=e[i].next) {
int t=e[i].t;
if (t==fat) {
continue;
}
dfs1(t,p);
val[p]+=val[t];
if (val[t]>max_son) {
son[p]=t;
max_son=val[t];
}
}
}
void dfs2(int p,int top_p) {
dfn[p]=++tot;
top[p]=top_p;
if (!son[p]) {
return;
}
dfs2(son[p],top_p);
for(int i=head[p];i+1;i=e[i].next) {
int t=e[i].t;
if (t==fa[p]||t==son[p]) {
continue;
}
dfs2(t,t);
}
}
int query_tree(int x) {
return query(rt,1,n,dfn[x],dfn[x]+val[x]-1);
}
void change_range(int x,int y,int val) {
while(top[x]!=top[y]) {
if (dep[top[x]]<dep[top[y]]) {
swap(x,y);
}
change(rt,1,n,dfn[top[x]],dfn[x],val);
x=fa[top[x]];
}
if (dep[x]>dep[y]) {
swap(x,y);
}
change(rt,1,n,dfn[x]+1,dfn[y],val);
}
//------------------------/
inline void init() {
memset(head,-1,sizeof(head));
memset(e,0,sizeof(e));
memset(son,0,sizeof(son));
memset(vis,0,sizeof(vis));
memset(node,0,sizeof(node));
cnt=tot=siz=con=0;
}
int main() {
int papapa=0;
read(n),read(m);
while(n&&m) {
init();
for(int i=1;i<=m;i++) {
read(E[i].x),read(E[i].y);
}
bulid_MST();
dfs1(1,1);
dfs2(1,1);
build(rt,1,n);
for(int i=1;i<=m;i++) {
if (!vis[i]) {
change_range(E[i].x,E[i].y,0);
}
}
read(q);
printf("Case %d:
",++papapa);
for(int i=1;i<=q;i++) {
int x,y;
read(x),read(y);
change_range(x,y,0);
printf("%d
",query_tree(1)-1);
}
printf("
");
read(n),read(m);
}
return 0;
}