ONTAK - 2010 - aut
给一棵
n
个点的树以及
q
次询问,统计满足以下条件的
恰经过一条额外的边
不经过树上
对于一个询问
dfs离线处理询问就行了。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
vector<int> adj[N],ext[N];
struct Query
{
int v,id;
};
vector<Query> q[N];
int n,Ans[N*5],sz[N],d[N],id[N],gg;
namespace LCA
{
int ord[N<<1],d[N<<1],fir[N],dp[N<<1][20],mm[N<<1],m=0;
void dfs_lca(int u,int p,int deep)
{
ord[++m]=u;
d[m]=deep;
fir[u]=m;
for(int i=0;i<adj[u].size();++i)
{
int v=adj[u][i];
if(v==p) continue;
dfs_lca(v,u,deep+1);
ord[++m]=u;
d[m]=deep;
}
}
void init_RMQ()
{
mm[0] = -1;
for(int i=1;i<=m;++i)
{
mm[i]= ((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
dp[i][0]=i;
}
for(int j=1;j<=mm[m];++j)
for(int i=1;i+(1<<j)-1<=m;++i)
{
int x=dp[i][j-1],y=dp[i+(1<<(j-1))][j-1];
dp[i][j]=d[x]<d[y]?x:y;
}
}
int lca(int u,int v)
{
u=fir[u],v=fir[v];
if(u>v) swap(u,v);
int k=mm[v-u+1];
int x=dp[u][k],y=dp[v-(1<<k)+1][k];
return d[x]<d[y]?ord[x]:ord[y];
}
void init(int u)
{
m=0;
dfs_lca(u,0,0);
init_RMQ();
}
}
namespace SegmentTree
{
int sum[N*9],s[N*9],top=0,tot=0,ls[N*9],rs[N*9];
int newnode()
{
int id;
if(top) id=s[--top];
else id=++tot;
sum[id]=ls[id]=rs[id]=0;
return id;
}
void delnode(int x)
{
s[top++]=x;
}
void build(int &rt,int l,int r,int p)
{
rt=newnode();
sum[rt]=1;
if(l==r) return ;
int mid=(l+r)>>1;
if(p<=mid) build(ls[rt],l,mid,p);
else build(rs[rt],mid+1,r,p);
}
int Merge(int rt1,int rt2)
{
if(rt1==0||rt2==0) return rt1^rt2;
ls[rt1]=Merge(ls[rt1],ls[rt2]);
rs[rt1]=Merge(rs[rt1],rs[rt2]);
sum[rt1]=sum[rt1]+sum[rt2];
delnode(rt2);
return rt1;
}
int query(int rt,int l,int r,int ql,int qr)
{
if(!rt) return 0;
if(ql<=l&&qr>=r) return sum[rt];
int mid=(l+r)>>1;
int res=0;
if(ql<=mid) res+=query(ls[rt],l,mid,ql,qr);
if(qr>mid) res+=query(rs[rt],mid+1,r,ql,qr);
return res;
}
int dfs(int u,int p)
{
int rt=newnode();
for(int i=0;i<adj[u].size();++i)
{
int v=adj[u][i];
if(v==p) continue;
Merge(rt,dfs(v,u));
}
for(int i=0;i<ext[u].size();++i)
{
int root=newnode();
build(root,1,n,id[ext[u][i]]);
Merge(rt,root);
}
for(int i=0;i<q[u].size();++i)
{
int v=q[u][i].v;
if(LCA::lca(u,v)==v)
{
int son;
for(int i=0;i<adj[v].size();++i)
if(LCA::lca(son=adj[v][i],u)==son&&d[son]>d[v]) break;
Ans[q[u][i].id]=query(rt,1,n,1,n)-query(rt,1,n,id[son],id[son]+sz[son]-1);
}
else Ans[q[u][i].id]=query(rt,1,n,id[v],id[v]+sz[v]-1);
}
return rt;
}
}
void dfs(int u,int p,int deep)
{
d[u]=deep;
sz[u]=1;
id[u]=++gg;
for(int i=0;i<adj[u].size();++i)
{
int v=adj[u][i];
if(v==p) continue;
dfs(v,u,deep+1);
sz[u]+=sz[v];
}
}
int main()
{
scanf("%d",&n);
for(int i=1; i<n; ++i)
{
int u,v;
scanf("%d%d",&u,&v);
adj[u].push_back(v);
adj[v].push_back(u);
}
dfs(1,0,0);
LCA::init(1);
int m;
scanf("%d",&m);
for(int i=0;i<m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
ext[u].push_back(v);
ext[v].push_back(u);
}
scanf("%d",&m);
for(int i=0;i<m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
if(d[u]>d[v]) q[u].push_back({v,i});
else q[v].push_back({u,i});
}
SegmentTree::dfs(1,0);
for(int i=0;i<m;++i)
printf("%d\n",Ans[i]+1);
return 0;
}