Description
给定一张无向图,每次删除一条边,每次询问两点间短程线上桥的数量
Solution
删除类问题时间倒流转化为加边
用 LCT 维护一个支撑树
对于每条树边维护一个权值,支持区间覆盖为 0
加边时,如果真的加在 LCT 上了把这个权值设为 1,如果没有加上,则把对应树上路径上的边权全部覆盖为 0
这样询问的答案就是对应树上路径的边权和
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000000;
int n,m,val[N];
namespace lct {
int top, q[N], ch[N][2], fa[N], rev[N], sum[N], tag[N];
inline void pushup(int x){
sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + val[x];
}
inline void puttag(int x) {
if(!x) return;
tag[x]=1;
sum[x]=0;
val[x]=0;
}
inline void pushdown(int x){
if(tag[x]) {
puttag(ch[x][0]);
puttag(ch[x][1]);
tag[x]=0;
}
if(!rev[x]) return;
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
rev[x]^=1;
swap(ch[x][0],ch[x][1]);
}
inline bool isroot(int x){
return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x;
}
inline void rotate(int p){
int q=fa[p], y=fa[q], x=ch[fa[p]][1]==p;
ch[q][x]=ch[p][x^1]; fa[ch[q][x]]=q;
ch[p][x^1]=q; fa[q]=p; fa[p]=y;
if(y) if(ch[y][0]==q) ch[y][0]=p;
else if(ch[y][1]==q) ch[y][1]=p;
pushup(q); pushup(p);
}
inline void splay(int x){
q[top=1]=x;
for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
for(int i=top;i;i--) pushdown(q[i]);
for(;!isroot(x);rotate(x))
if(!isroot(fa[x]))
rotate((ch[fa[x]][0]==x)==(ch[fa[fa[x]]][0]==fa[x])?fa[x]:x);
}
void access(int x){
for(int t=0;x;t=x,x=fa[x])
splay(x),ch[x][1]=t,pushup(x);
}
void makeroot(int x){
access(x);
splay(x);
rev[x]^=1;
}
int find(int x){
access(x);
splay(x);
while(ch[x][0]) x=ch[x][0];
return x;
}
void split(int x,int y){
makeroot(x);
access(y);
splay(y);
}
void cut(int x,int y){
split(x,y);
if(ch[y][0]==x)
ch[y][0]=0, fa[x]=0;
}
void link(int x,int y){
makeroot(x);
fa[x]=y;
pushup(y);
}
int query(int x,int y) {
if(find(x)!=find(y)) return 0;
split(x,y);
return sum[y];
}
void modify(int x,int y) {
split(x,y);
puttag(y);
}
}
struct edge {
int u,v;
edge() {
u=v=0;
}
edge(int a,int b) {
u=min(a,b);
v=max(a,b);
}
bool operator < (const edge &x) const {
return u==x.u ? v<x.v : u<x.u;
}
bool operator == (const edge &x) const {
return u==x.u && v==x.v;
}
} ed[N];
map<int,int> mp;
int t1,t2,t3,ind,fg[N];
struct operating {
int op,u,v;
};
int idedge(int u,int v) {
if(u>v) swap(u,v);
return u*N+v;
}
vector <operating> vec;
vector <int> ans;
void linkedge(int i) {
if(lct::find(ed[i].u)==lct::find(ed[i].v)) {
lct::modify(ed[i].u,ed[i].v);
}
else {
lct::link(ed[i].u,i);lct::link(ed[i].v,i);
}
}
signed main() {
ios::sync_with_stdio(false);
cin>>n>>m;
ind=n;
for(int i=1;i<=m;i++) {
cin>>t1>>t2;
mp[idedge(t1,t2)]=++ind;
ed[ind]=edge(t1,t2);
}
while(true) {
cin>>t1;
if(t1==-1) {
break;
}
cin>>t2>>t3;
vec.push_back({t1,t2,t3});
if(t1==0) {
fg[mp[idedge(t2,t3)]]=1;
}
}
reverse(vec.begin(),vec.end());
for(int i=n+1;i<=n+m;i++) {
val[i]=1;
}
for(int i=n+1;i<=n+m;i++) {
if(fg[i]==0) {
linkedge(i);
}
}
for(operating now:vec) {
if(now.op==0) {
int i=mp[idedge(now.u,now.v)];
linkedge(i);
}
else {
ans.push_back(lct::query(now.u,now.v));
}
}
while(ans.size()) {
cout<<*ans.rbegin()<<endl;
ans.pop_back();
}
}