BZOJ1969 [Ahoi2005]LANE 航线规划

题面在这里

直接离线倒序加边,一开始一定有一棵树

不断加入非树边构成双联通分量

答案就是两点之间不在环上的边的条数

用树链剖分维护边的情况即可

示例程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include<cstdio>
#include<algorithm>
using namespace std;
inline char nc(){
static char buf[100000],*l=buf,*r=buf;
return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
inline int red(){
int res=0,f=1;char ch=nc();
while (ch<'0'||'9'<ch) {if (ch=='-') f=-f;ch=nc();}
while ('0'<=ch&&ch<='9') res=res*10+ch-48,ch=nc();
return res*f;
}

const int maxn=30005,maxe=100005,maxs=120005;
int n,e,q,fa[maxn],ans[maxe];
bool dmg[maxe];
struct edge{
int x,y;
edge () {}
edge (int _x,int _y):x(_x),y(_y) {}
bool operator<(const edge&b)const {return x<b.x||x==b.x&&y<b.y;}
}a[maxe];
struct ask{
int x,y,c;
}Q[maxe];
int son[maxe],lnk[maxn],nxt[maxe],tot;
inline void add(int x,int y){
son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;
}
inline int getfa(int x) {return fa[x]==x?x:fa[x]=getfa(fa[x]);}
int dep[maxn],siz[maxn],Hson[maxn],top[maxn],dfn[maxn],times;
void getdep(int x){
siz[x]=1;dep[x]=dep[fa[x]]+1;Hson[x]=0;
for (int j=lnk[x];j;j=nxt[j])
if (son[j]!=fa[x]){
fa[son[j]]=x; getdep(son[j]); siz[x]+=siz[son[j]];
if (!Hson[x]||siz[Hson[x]]<siz[son[j]]) Hson[x]=son[j];
}
}
void dfs(int x,int lst){
top[x]=lst;dfn[x]=++times;
if (Hson[x]) dfs(Hson[x],lst);
for (int j=lnk[x];j;j=nxt[j])
if (son[j]!=Hson[x]&&son[j]!=fa[x]) dfs(son[j],son[j]);
}
int s[maxs],cv[maxs];
inline void pushup(int x) {s[x]=s[x<<1]+s[x<<1|1];}
inline void addcv(int x,int l,int r) {s[x]=r-l+1,cv[x]=1;}
inline void pushdown(int x,int l,int r,int mid){if (cv[x]) addcv(x<<1,l,mid),addcv(x<<1|1,mid+1,r),cv[x]=0;}
void ist(int x,int l,int r,int ql,int qr){
if (ql<=l&&r<=qr) return addcv(x,l,r);
if (qr<l||r<ql) return;
int mid=l+r>>1; pushdown(x,l,r,mid);
ist(x<<1,l,mid,ql,qr); ist(x<<1|1,mid+1,r,ql,qr);
pushup(x);
}
int qry(int x,int l,int r,int ql,int qr){
if (ql<=l&&r<=qr) return s[x];
if (qr<l||r<ql) return 0;
int mid=l+r>>1; pushdown(x,l,r,mid);
return qry(x<<1,l,mid,ql,qr)+qry(x<<1|1,mid+1,r,ql,qr);
}
void insert(int x,int y){
while (top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) swap(x,y);
ist(1,1,n,dfn[top[x]],dfn[x]); x=fa[top[x]];
}
if (dfn[x]>dfn[y]) swap(x,y);
ist(1,1,n,dfn[x]+1,dfn[y]);
}
int query(int x,int y){
int res=0;
while (top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) swap(x,y);
res+=dfn[x]-dfn[top[x]]+1-qry(1,1,n,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if (dfn[x]>dfn[y]) swap(x,y);
return res+dfn[y]-dfn[x]-qry(1,1,n,dfn[x]+1,dfn[y]);
}
int main(){
n=red(),e=red();
for (int i=1;i<=e;i++){
a[i].x=red(),a[i].y=red();
if (a[i].x>a[i].y) swap(a[i].x,a[i].y);
}
sort(a+1,a+1+e);
for (int c=red();c!=-1;c=red()){
q++;Q[q].x=red(),Q[q].y=red(),Q[q].c=c;
if (Q[q].x>Q[q].y) swap(Q[q].x,Q[q].y);
if (c==0) dmg[lower_bound(a+1,a+1+e,edge(Q[q].x,Q[q].y))-a]=1;
}
for (int i=1;i<=n;i++) fa[i]=i;
for (int i=1;i<=e;i++)
if (!dmg[i]&&getfa(a[i].x)!=getfa(a[i].y)){
fa[getfa(a[i].x)]=getfa(a[i].y);
add(a[i].x,a[i].y); add(a[i].y,a[i].x);
dmg[i]=1;
}
fa[1]=1;getdep(1);dfs(1,1);
for (int i=1;i<=e;i++)
if (!dmg[i]) insert(a[i].x,a[i].y);
for (int i=q;i>=1;i--)
if (Q[i].c) ans[i]=query(Q[i].x,Q[i].y);else insert(Q[i].x,Q[i].y);
for (int i=1;i<=q;i++)
if (Q[i].c) printf("%d\n",ans[i]);
return 0;
}