BZOJ 3572 世界树
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
61
5
2 7 3 6 9
1
8
4
8 7 10 3
5
2 9 3 5 8
Sample Output
1 9
3 1 4 1 1
1 0
1 1 3 5
4 1 3 1 1
HINT
N<=300000, q<=300000,m[1]+m[2]+…+m[q]<=300000
Source
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<algorithm> 6 using namespace std; 7 8 #define maxn 300010 9 int side[maxn],next[maxn*2],f[maxn][25],tmp[maxn],stack[maxn],DFN; 10 int toit[maxn*2],dfn[maxn],dep[maxn],ask[maxn],size[maxn],tree[maxn],cnt,n; 11 int ans[maxn],father[maxn],val[maxn],in[maxn]; pair <int,int> near[maxn]; 12 13 inline bool cmp(int a,int b) { return dfn[a] < dfn[b]; } 14 15 inline void add(int a,int b) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; } 16 17 inline void ins(int a,int b) { add(a,b); add(b,a); } 18 19 inline void dfs(int now) 20 { 21 dfn[now] = ++DFN; 22 for (int i = 1;(1 << i)<=dep[now];++i) f[now][i] = f[f[now][i-1]][i-1]; 23 for (int i = side[now];i;i = next[i]) 24 if (toit[i]!=f[now][0]) 25 { 26 f[toit[i]][0] = now; dep[toit[i]] = dep[now]+1; 27 dfs(toit[i]);size[now] += size[toit[i]]; } 28 size[now]++; 29 } 30 31 inline void jump(int &a,int step) 32 { 33 for (int i = 0;step;step >>= 1,++i) 34 if (step&1) a = f[a][i]; 35 } 36 37 inline int lca(int a,int b) 38 { 39 if (dep[a] < dep[b]) swap(a,b); 40 jump(a,dep[a]-dep[b]); 41 if (a == b) return a; 42 for (int i = 0;i >= 0;) 43 { 44 if (f[a][i] != f[b][i]) a = f[a][i],b = f[b][i],++i; 45 else --i; 46 } 47 return f[a][0]; 48 } 49 50 inline int find(int now,int d) 51 { 52 for (int i = 0;i>=0&&dep[now]>d;) 53 { 54 if (dep[f[now][i]] >= d) now = f[now][i],++i; 55 else --i; 56 } 57 return now; 58 } 59 60 inline void solve() 61 { 62 int k; scanf("%d ",&k); 63 for (int i = 1;i <= k;++i) 64 { 65 scanf("%d",ask+i),tree[i] = tmp[i] = ask[i]; 66 near[ask[i]] = make_pair(0,ask[i]); ans[ask[i]] = 0; 67 } 68 sort(ask+1,ask+k+1,cmp); 69 int top = 0,tot = k; 70 for (int i = 1;i <= k;++i) 71 { 72 int p = ask[i]; 73 if (!top) stack[++top] = p,father[p] = 0; 74 else 75 { 76 int x = lca(stack[top],p); 77 father[p] = x; 78 while (top&&dep[stack[top]] > dep[x]) 79 { 80 if (dep[stack[top-1]] <= dep[x]) 81 father[stack[top]] = x; 82 --top; 83 } 84 if (stack[top] != x) 85 { 86 father[x] = stack[top]; tree[++tot] = x; 87 stack[++top] = x; near[x] = make_pair(1<<30,0); 88 } 89 stack[++top] = p; 90 } 91 } 92 sort(tree+1,tree+tot+1,cmp); 93 for (int i = 1;i <= tot;++i) 94 { 95 int p = tree[i]; val[p] = size[p]; 96 if (i > 1) in[p] = dep[p]-dep[father[p]]; 97 } 98 for (int i = tot;i > 1;--i) 99 { 100 int p = tree[i],fa = father[p]; 101 near[fa] = min(near[fa],make_pair(near[p].first+in[p],near[p].second)); 102 } 103 for (int i = 2;i <= tot;++i) 104 { 105 int p = tree[i],fa = father[p]; 106 near[p] = min(near[p],make_pair(near[fa].first+in[p],near[fa].second)); 107 } 108 for (int i = 1;i <= tot;++i) 109 { 110 int p = tree[i],fa = father[p],sum = size[find(p,dep[fa]+1)]-size[p]; 111 if (fa == 0) ans[near[p].second] += n-size[p]; 112 else 113 { 114 val[fa] -= sum+size[p]; 115 if (near[p].second == near[fa].second) 116 ans[near[p].second] += sum; 117 else 118 { 119 int dis = (dep[p]-dep[fa]-near[p].first+near[fa].first)>>1; 120 if (dis+near[p].first==near[fa].first+dep[p]-dep[fa]-dis&&near[fa].second<near[p].second) 121 --dis; 122 int x = find(p,dep[p]-dis); 123 ans[near[p].second] += size[x]-size[p]; 124 ans[near[fa].second] += sum+size[p]-size[x]; 125 } 126 } 127 } 128 for (int i = 1;i <= tot;++i) 129 ans[near[tree[i]].second] += val[tree[i]]; 130 for (int i = 1;i <= k;++i) printf("%d ",ans[tmp[i]]); 131 puts(""); 132 } 133 134 int main() 135 { 136 freopen("3572.in","r",stdin); 137 freopen("3572.out","w",stdout); 138 scanf("%d",&n); 139 for (int i = 1;i < n;++i) { int x,y; scanf("%d %d",&x,&y); ins(x,y); } 140 dfs(1); 141 int T; scanf("%d",&T); 142 while (T--) solve(); 143 return 0; 144 }