3572: [Hnoi2014]世界树
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1385 Solved: 762
[ Submit][ Status][ Discuss]
Description
世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。
世界树的形态可以用一个数学模型来描述:世界树中有n个种族,种族的编号分别从1到n,分别生活在编号为1到n的聚居地上,种族的编号与其聚居地的编号相同。有的聚居地之间有双向的道路相连,道路的长度为1。保证连接的方式会形成一棵树结构,即所有的聚居地之间可以互相到达,并且不会出现环。定义两个聚居地之间的距离为连接他们的道路的长度;例如,若聚居地a和b之间有道路,b和c之间有道路,因为每条道路长度为1而且又不可能出现环,所卧a与c之间的距离为2。
出于对公平的考虑,第i年,世界树的国王需要授权m[i]个种族的聚居地为临时议事处。对于某个种族x(x为种族的编号),如果距离该种族最近的临时议事处为y(y为议事处所在聚居地的编号),则种族x将接受y议事处的管辖(如果有多个临时议事处到该聚居地的距离一样,则y为其中编号最小的临时议事处)。
现在国王想知道,在q年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。 现在这个任务交给了以智慧著称的灵长类的你:程序猿。请帮国王完成这个任务吧。
Input
第一行为一个正整数n,表示世界树中种族的个数。
接下来n-l行,每行两个正整数x,y,表示x聚居地与y聚居地之间有一条长度为1的双
向道路。接下来一行为一个正整数q,表示国王询问的年数。
接下来q块,每块两行:
第i块的第一行为1个正整数m[i],表示第i年授权的临时议事处的个数。
第i块的第二行为m[i]个正整数h[l]、h[2]、…、h[m[i]],表示被授权为临时议事处的聚居地编号(保证互不相同)。
Output
输出包含q行,第i行为m[i]个整数,该行的第j(j=1,2…,,m[i])个数表示第i年被授权的聚居地h[j]的临时议事处管理的种族个数。
Sample Input
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
Sample Output
3 1 4 1 1
10
1 1 3 5
4 1 3 1 1
HINT
N<=300000, q<=300000,m[1]+m[2]+…+m[q]<=300000
Source
很显然是构建一棵虚树,然后在虚树上dp,但是细节挺多的。。。
每次询问,先将虚树构建出来,然后可以这样考虑
部落对答案的共线分配到点和链上,分开统计
比如,对于虚树的叶子节点,这个节点在原树中的子树的所有部落肯定都归它管了
还有是虚树的根节点,在原树中,处于这个根之外的所有节点先走到根,然后找一个议事处给它
其它节点也类似这样处理,也就是把不在虚树上的点当做点权
然后是虚树上的边,每条边的实质是原树的一条链,链上的点也是有后代的
所以统计链上的答案时先讨论出分界点然后用子树大小作差一下
过程繁琐。。写了才知道。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn = 3E5 + 30;
const int T = 19;
struct E{
int to,w; E(){}
E(int to,int w): to(to),w(w){}
};
int n,tp,dfs_clock,N,A[maxn],B[maxn],dfn[maxn],stk[maxn],siz[maxn],L[maxn],
fr[maxn],sc[maxn],nf[maxn],ns[maxn],bel[maxn],val[maxn],Ans[maxn],fa[maxn][T];
bool key[maxn];
vector <int> v[maxn];
vector <E> g[maxn];
stack <int> s;
int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret * 10 + ch - '0',ch = getchar();
return ret;
}
int LCA(int p,int q)
{
if (L[p] < L[q]) swap(p,q);
for (int i = T - 1; i >= 0; i--)
if (L[p] - (1 << i) >= L[q])
p = fa[p][i];
if (p == q) return p;
for (int i = T - 1; i >= 0; i--)
if (fa[p][i] != fa[q][i])
p = fa[p][i],q = fa[q][i];
return fa[p][0];
}
int Quickfa(int x,int y)
{
for (int now = 0; y; y >>= 1,++now)
if (y & 1) x = fa[x][now];
return x;
}
void Dfs1(int x,int from)
{
siz[x] = 1; dfn[x] = ++dfs_clock;
for (int i = 1; i < T; i++) fa[x][i] = fa[fa[x][i-1]][i-1];
for (int i = 0; i < v[x].size(); i++)
{
int to = v[x][i];
if (to == from) continue;
L[to] = L[x] + 1; fa[to][0] = x;
Dfs1(to,x); siz[x] += siz[to];
}
}
void Dfs2(int x)
{
bool flag = 0; val[x] = siz[x]; fr[x] = sc[x] = maxn;
if (key[x]) fr[x] = 0,nf[x] = x,bel[x] = -1;
for (int i = 0; i < g[x].size(); i++)
{
E e = g[x][i]; Dfs2(e.to);
val[x] -= siz[Quickfa(e.to,L[e.to]-L[x]-1)];
int now = fr[e.to] + e.w; flag = 1;
if (now < fr[x])
{
sc[x] = fr[x]; ns[x] = nf[x];
fr[x] = now; nf[x] = nf[e.to]; bel[x] = i;
}
else if (now == fr[x])
{
if (nf[e.to] < nf[x])
{
sc[x] = fr[x]; ns[x] = nf[x];
fr[x] = now; nf[x] = nf[e.to]; bel[x] = i;
}
else
{
if (sc[x] == now) ns[x] = min(ns[x],nf[e.to]);
else sc[x] = now,ns[x] = nf[e.to];
}
}
else if (now < sc[x]) sc[x] = now,ns[x] = nf[e.to];
else if (now == sc[x]) ns[x] = min(ns[x],nf[e.to]);
}
}
void Dfs3(int x,int Num,int dis)
{
if (key[x]) Num = x,dis = 0;
if (dis < fr[x]) Ans[Num] += val[x];
else if (dis > fr[x]) Ans[nf[x]] += val[x];
else if (Num < nf[x]) Ans[Num] += val[x];
else Ans[nf[x]] += val[x];
for (int i = 0; i < g[x].size(); i++)
{
E e = g[x][i]; int tot = e.w - 1;
int Nex,len;
if (i == bel[x])
{
if (sc[x] < dis) len = sc[x],Nex = ns[x];
else if (sc[x] > dis) len = dis,Nex = Num;
else if (ns[x] < Num) len = sc[x],Nex = ns[x];
else len = dis,Nex = Num;
}
else
{
if (fr[x] < dis) len = fr[x],Nex = nf[x];
else if (fr[x] > dis) len = dis,Nex = Num;
else if (nf[x] < Num) len = fr[x],Nex = nf[x];
else len = dis,Nex = Num;
}
if (tot)
{
int y = Quickfa(e.to,L[e.to]-L[x]-1);
int tmp = fr[e.to] + tot + 1 - len;
if (tmp > 0 && !(tmp&1) && tot >= (tmp >> 1))
{
int k = (tmp >> 1);
int z = Quickfa(e.to,tot-k+1);
Ans[Nex] += siz[y] - siz[z];
y = Quickfa(e.to,tot-k);
Ans[nf[e.to]] += siz[y] - siz[e.to];
if (Nex < nf[e.to]) Ans[Nex] += siz[z] - siz[y];
else Ans[nf[e.to]] += siz[z] - siz[y];
}
else if (len + tot < fr[e.to] + 1) Ans[Nex] += siz[y] - siz[e.to];
else if (fr[e.to] + tot < len + 1) Ans[nf[e.to]] += siz[y] - siz[e.to];
else
{
int k = fr[e.to] + tot - len >> 1;
int z = Quickfa(e.to,tot-k);
Ans[Nex] += siz[y] - siz[z];
Ans[nf[e.to]] += siz[z] - siz[e.to];
}
}
Dfs3(e.to,Nex,len + e.w);
}
}
bool cmp(const int &x,const int &y) {return dfn[x] < dfn[y];}
void Work()
{
N = getint();
for (int i = 1; i <= N; i++)
A[i] = B[i] = getint(),key[A[i]] = 1;
sort(A + 1,A + N + 1,cmp); stk[tp = 1] = A[1]; s.push(A[1]);
for (int i = 2; i <= N; i++)
{
int k = A[i],lca = LCA(k,stk[tp]);
if (lca == stk[tp]) stk[++tp] = k;
else
{
for (;;)
{
if (L[stk[tp-1]] > L[lca])
g[stk[tp-1]].push_back(E(stk[tp],L[stk[tp]]-L[stk[tp-1]])),--tp;
else
{
g[lca].push_back(E(stk[tp],L[stk[tp]]-L[lca])); --tp;
if (L[stk[tp]] < L[lca]) stk[++tp] = lca,s.push(lca); break;
}
}
stk[++tp] = k;
}
s.push(k);
}
int rt = stk[1];
while (tp > 1) g[stk[tp-1]].push_back(E(stk[tp],L[stk[tp]]-L[stk[tp-1]])),--tp;
Dfs2(rt); val[rt] += n - siz[rt]; Dfs3(rt,0,maxn);
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
n = getint();
for (int i = 1; i < n; i++)
{
int x = getint(),y = getint();
v[x].push_back(y);
v[y].push_back(x);
}
L[1] = 1; Dfs1(1,0);
int q = getint();
for (int I = 1; I <= q; I++)
{
Work();
for (int i = 1; i <= N; i++) printf("%d ",Ans[B[i]]);
puts("");
while (!s.empty())
{
int k = s.top(); s.pop();
g[k].clear(); val[k] = key[k] = Ans[k] = 0;
}
}
return 0;
}