虚树裸题,正反DP一遍求答案。
写了一发rmqlca发现比倍增慢。。这个显然调用超过n次了啊。。为什么
O(nlogn)
预处理
O(1)
查询会比超过
n
次
bzoj傻逼样例没空格,样例在程序最下面。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 300005
using namespace std;
int n,m,Q,cnt,dfn,top,eul;
int fa[N][20];
int a[N],b[N],f[N],stack[N],point[N],rem[N],belong[N],deep[N],head[N],id[N],size[N],pos[N];
int next[N<<1],list[N<<1];
pair<int,int> ss[N<<1],st[N<<1][21];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline void insert(int x,int y)
{
next[++cnt]=head[x];
head[x]=cnt;
list[cnt]=y;
}
void dfs(int x)
{
id[x]=++dfn; size[x]=1; ss[++eul]=make_pair(deep[x],x); pos[x]=eul;
for (int i=1;(1<<i)<=deep[x];i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for (int i=head[x];i;i=next[i])
if (list[i]!=fa[x][0])
{
fa[list[i]][0]=x;
deep[list[i]]=deep[x]+1;
dfs(list[i]);
size[x]+=size[list[i]];
ss[++eul]=make_pair(deep[x],x);
}
}
inline void make_st()
{
for (int i=1;i<=eul;i++) st[i][0]=ss[i];
for (int j=1;j<=20;j++)
for (int i=1;i<=eul;i++)
if (i+(1<<j)-1<=eul)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
inline int lca(int x,int y)
{
int l=pos[x],r=pos[y];
if (l>r) swap(l,r);
int k=log2(r-l+1);
pair<int,int> ans=min(st[l][k],st[r-(1<<k)+1][k]);
return ans.second;
}
inline bool cmp(int a,int b)
{
return id[a]<id[b];
}
inline int dis(int x,int y)
{
return deep[x]+deep[y]-(deep[lca(x,y)]<<1);
}
void dp1(int x)
{
point[++dfn]=x; rem[x]=size[x];
for (int i=head[x];i;i=next[i])
{
dp1(list[i]);
if (!belong[list[i]]) continue;
int t1=dis(belong[list[i]],x),t2=dis(belong[x],x);
if (t1<t2||!belong[x]||(t1==t2&&belong[list[i]]<belong[x]))
belong[x]=belong[list[i]];
}
}
void dp2(int x)
{
for (int i=head[x];i;i=next[i])
{
int t1=dis(belong[x],list[i]),t2=dis(belong[list[i]],list[i]);
if (t1<t2||!belong[list[i]]||(t1==t2&&belong[x]<belong[list[i]]))
belong[list[i]]=belong[x];
dp2(list[i]);
}
}
void solve(int a,int b)
{
int x=b,mid=b;
for (int i=18;~i;i--)
if (deep[fa[x][i]]>deep[a])
x=fa[x][i];
rem[a]-=size[x];
if (belong[a]==belong[b])
{
f[belong[a]]+=size[x]-size[b];
return;
}
for (int i=18;~i;i--)
{
if (deep[fa[mid][i]]<=deep[a]) continue;
int t=fa[mid][i];
int t1=dis(belong[a],t),t2=dis(t,belong[b]);
if (t1>t2||(t1==t2&&belong[a]>belong[b])) mid=t;
}
f[belong[a]]+=size[x]-size[mid];
f[belong[b]]+=size[mid]-size[b];
}
inline void query()
{
m=read();
for (int i=1;i<=m;i++) a[i]=b[i]=read();
for (int i=1;i<=m;i++) belong[a[i]]=a[i];
sort(a+1,a+m+1,cmp);
top=0; dfn=0; cnt=0;
if (belong[1]!=1) stack[++top]=1;
for (int i=1;i<=m;i++)
{
int t=a[i],f;
while (top)
{
f=lca(stack[top],t);
if (top>1&&deep[f]<deep[stack[top-1]])
insert(stack[top-1],stack[top]),top--;
else if (deep[f]<deep[stack[top]])
{
insert(f,stack[top]);
top--;
break;
}
else break;
}
if (stack[top]!=f) stack[++top]=f; stack[++top]=t;
}
while (top>1) insert(stack[top-1],stack[top]),top--;
dp1(1); dp2(1);
for (int i=1;i<=dfn;i++)
for (int j=head[point[i]];j;j=next[j])
solve(point[i],list[j]);
for (int i=1;i<=dfn;i++)
f[belong[point[i]]]+=rem[point[i]];
for (int i=1;i<=m;i++)
printf("%d ",f[b[i]]);
puts("");
for (int i=1;i<=dfn;i++)
head[point[i]]=rem[point[i]]=belong[point[i]]=f[point[i]]=0;
}
int main()
{
n=read();
for (int i=1;i<n;i++)
{
int u=read(),v=read();
insert(u,v); insert(v,u);
}
dfs(1);
make_st();
memset(head,0,sizeof(head));
Q=read();
while (Q--) query();
return 0;
}
/*
10
2 1
3 2
4 3
5 4
6 1
7 3
8 3
9 4
10 1
5
2
6 1
5
2 7 3 6 9
1
8
4
8 7 10 3
5
2 9 3 5 8
1 9
3 1 4 1 1
10
1 1 3 5
4 1 3 1 1
*/