标准对树进行树链剖分,并用树状数组维护连续区间和问题。树状数组维护两点u,v对应的【tid【u】,tid【v】】区间是否有点已经被破坏。
代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define n 10005
const int maxn=50000+5;
vector<int>p[n];
int in[n],out[n],dep[n],fa[n];
int son[n],siz[n],tep[n],c[n],tot,nn;
struct node{
int u,v,lca;
friend bool operator<(node n1,node n2){
return dep[n1.lca]<dep[n2.lca];
}
}g[maxn];
bool cmp(node a,node b){
return b<a;
}
void addedge(int u,int v){
p[u].push_back(v);
p[v].push_back(u);
}
void init(int x){
tot=0;
for (int i=1; i<=x+1;i++){
son[i]=-1;
siz[i]=1;
p[i].clear();
c[i]=0;
}
}
void dfs1(int u,int father,int dp){
in[u]=++tot;
dep[u]=dp;
fa[u]=father;
for (int i=0; i<p[u].size(); i++) {
int v=p[u][i];
if (v!=father) {
dfs1(v, u, dp+1);
siz[u]+=siz[v];
if (son[u]==-1||siz[son[u]]<siz[v]) {
son[u]=v;
}
}
}
out[u]=tot;
}
void dfs2(int u,int tp){
tep[u]=tp;
if (son[u]==-1) {
return;
}
dfs2(son[u], tp);
for (auto v:p[u]) {
if (v==fa[u]||v==son[u]) {
continue;
}
dfs2(v, v);
}
}
int lca(int u,int v){
while (tep[u]!=tep[v]) {
if (dep[tep[u]]<dep[tep[v]]) {
swap(u, v);
}
u=fa[tep[u]];
}
if (dep[u]>dep[v]) {
swap(u, v);
}
return u;
}
int lowbit(int x){
return x&(-x);
}
int sum(int x){
int ans=0;
while (x) {
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
void change(int x,int y){
while (x<n) {
c[x]+=y;
x+=lowbit(x);
}
}
int main(){
while (scanf("%d",&nn)!=EOF) {
init(nn);
for (int i=0; i<nn; i++) {
int u,v;
scanf("%d%d",&u,&v);
u++;v++;
addedge(u,v);
}
nn++;
dfs1(1, -1, 1);
dfs2(1, 1);
int q;
cin>>q;
for (int i=0; i<q; i++) {
scanf("%d%d",&g[i].u,&g[i].v);
g[i].u++;g[i].v++;
g[i].lca=lca(g[i].u, g[i].v);
}
sort(g,g+q,cmp);
int ans=0;
for (int i=0; i<q; i++) {
int u=g[i].u,v=g[i].v,lc=g[i].lca;
int num=sum(in[u])+sum(in[v]);
if (!num) {
ans++;
change(in[lc],1);
change(out[lc]+1,-1);
}
}
cout<<ans<<endl;
}
return 0;
}