树链剖分 (Tarjan)
首先和水管局长(自己的链接)一样,先把边删完,建出最终的图。然后把操作倒过来,转删边为添边。
然后有两种方法把这张图变成树:
1.建出这个图的一颗生成树,把其他多余的边当作添边处理。
2.Tarjan缩点后处理。
对这个树进行树链剖分维护边权(刚开始都是1)。添边就把这两个点的路径上的边权都变成0,询问就直接查询路径点权和即可。
代码采用的是第二种做法,因为我第一种方法没调出来直接。但第一种做法代码量会小很多。
代码(太长了我分分段):
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 30005
#define K 40005
#define M 100005
#define F inline
using namespace std;
struct tree{ int l,r,f,sum; }t[N<<2];
struct edge{ int next,to; }ed[M<<2];
struct edg{ int x,y,id; }e[M];
struct query{ int x,y,f; }q[K];
int n,m,k,nd,p,ti,fa[N][20],dep[N],tp[N],to[N],sz[N],id[N],in[N];
int top,kk,nq,np,stk[N],dfn[N],low[N],num[N],h1[N],h[N],ans[K];
bool f[N];
//IO优化
F char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; return *l++;
}
F int _read(){
int x=0,f=1; char ch=readc();
while (!isdigit(ch)) { if (ch=='-') f=-1; ch=readc(); }
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x*f;
}
F void writec(int x){ if (x>9) writec(x/10); putchar(x%10+48); }
F void _write(int x){ writec(x),putchar('\n'); }
F bool cmp(edg a,edg b){ return a.x==b.x?a.y<b.y:a.x<b.x; }
F void addedge(int *h,int x,int y){ ed[++k]=(edge){h[x],y},h[x]=k; }
F int ef(int x,int y){
int l=1,r=m,mid;
while (l<=r){
int p=e[mid=l+r>>1].x,q=e[mid].y;
if (p<x||p==x&&q<y) l=mid+1;
else if (p>x||p==x&&q>y) r=mid-1;
else return mid;
}
}
//树剖的两遍DFS
void dfs1(int x,int dth){
sz[x]=1,dep[x]=dth;
for (int i=h[x],v;i;i=ed[i].next)
if ((v=ed[i].to)!=fa[x][0]){
fa[v][0]=x,dfs1(v,dth+1),sz[x]+=sz[v];
if (sz[to[x]]<sz[v]) to[x]=v;
}
}
void dfs2(int x){
if (to[in[id[x]=++nd]=x]) tp[to[x]]=tp[x],dfs2(to[x]);
for (int i=h[x],v;i;i=ed[i].next)
if ((v=ed[i].to)!=fa[x][0]&&v!=to[x])
tp[v]=v,dfs2(v);
}
//线段树
F void pshd(int x){
t[x<<1].f=t[x<<1|1].f=t[x].f,t[x].f=-1;
t[x<<1].sum=(t[x<<1].r-t[x<<1].l+1)*t[x<<1].f;
t[x<<1|1].sum=(t[x<<1|1].r-t[x<<1|1].l+1)*t[x<<1|1].f;
}
void build(int x,int l,int r){
t[x].l=l,t[x].r=r,t[x].sum=r-l+1,t[x].f=-1;
if (l==r) return; int mid=l+r>>1;
build(x<<1,l,mid),build(x<<1|1,mid+1,r);
}
void mdfy(int x,int l,int r,int w){
if (t[x].r<l||t[x].l>r) return;
if (t[x].l>=l&&t[x].r<=r){
t[x].f=w,t[x].sum=(t[x].r-t[x].l+1)*w; return;
}
if (~t[x].f) pshd(x);
mdfy(x<<1,l,r,w),mdfy(x<<1|1,l,r,w);
t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
}
int srch(int x,int l,int r){
if (t[x].r<l||t[x].l>r) return 0;
if (t[x].l>=l&&t[x].r<=r) return t[x].sum;
if (~t[x].f) pshd(x);
return srch(x<<1,l,r)+srch(x<<1|1,l,r);
}
//树剖
F void nsrt(int x,int y){
while (tp[x]!=tp[y]){
if (dep[tp[x]]<dep[tp[y]]) swap(x,y);
mdfy(1,id[tp[x]],id[x],0),x=fa[tp[x]][0];
}
if (dep[x]<dep[y]) swap(x,y);
mdfy(1,id[y],id[x],0);
}
F int find(int x,int y){
int ans=0;
while (tp[x]!=tp[y]){
if (dep[tp[x]]<dep[tp[y]]) swap(x,y);
ans+=srch(1,id[tp[x]],id[x]),x=fa[tp[x]][0];
}
if (dep[x]<dep[y]) swap(x,y);
return ans+srch(1,id[y],id[x]);
}
//缩点
void Tarjan(int x,int e){
low[x]=dfn[x]=++p,stk[++top]=x,f[x]=true;
for (int i=h1[x],v;i;i=ed[i].next)
if (i!=e)
if (!dfn[v=ed[i].to])
Tarjan(v,i^1),low[x]=min(low[x],low[v]);
else low[x]=min(low[x],dfn[v]);
if (low[x]==dfn[x]){
ti++;
while (stk[top+1]!=x)
num[stk[top]]=ti,f[stk[top--]]=false;
}
}
//LCA
F void Make(){
for (int j=1;j<=16;j++)
for (int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
F int LCA(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
for (int j=16;~j;j--)
if (dep[fa[x][j]]>=dep[y]) x=fa[x][j];
if (x==y) return x;
for (int j=16;~j;j--)
if (fa[x][j]!=fa[y][j])
x=fa[x][j],y=fa[y][j];
return fa[x][0];
}
int main(){
n=_read(),m=_read(),k=1;
for (int i=1,x,y;i<=m;i++){
x=_read(),y=_read(); if (x>y) swap(x,y);
e[++kk]=(edg){x,y,0};
}
sort(e+1,e+kk+1,cmp);
for (int fl=_read(),x,y;~fl;fl=_read()){
x=_read(),y=_read(); if (x>y) swap(x,y);
q[++nq].f=fl,q[nq].x=x,q[nq].y=y;
if (!fl) e[ef(x,y)].id=1,np++;
}
for (int i=1;i<=kk;i++)
if (!e[i].id){
addedge(h1,e[i].x,e[i].y);
addedge(h1,e[i].y,e[i].x);
}
for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i,0);
for (int i=1;i<=n;i++)
for (int j=h1[i],v;j;j=ed[j].next)
if (num[i]!=num[ed[j].to])
addedge(h,num[i],num[ed[j].to]);
dfs1(1,1),tp[1]=1,dfs2(1),build(1,1,n),Make();
for (int i=nq;i;i--){
int x=num[q[i].x],y=num[q[i].y],lca=LCA(x,y),lst;
if (!q[i].f){
lst=srch(1,id[lca],id[lca]),nsrt(x,y);
if (lst) mdfy(1,id[lca],id[lca],1);
}
else ans[++ans[0]]=find(x,y)-find(lca,lca);
}
for (int i=ans[0];i;i--) _write(ans[i]); return 0;
}