CF1009F Dominant Indices
题面:
题目描述
你得到一个包含 n n n 个顶点的无向树,顶点 1 1 1 是树的根。
我们将顶点 x x x 的深度数组定义为一个无限序列 [ d x , 0 , d x , 1 , d x , 2 , … ] [d_{x, 0}, d_{x, 1}, d_{x, 2}, \dots] [dx,0,dx,1,dx,2,…],其中 d x , i d_{x, i} dx,i 是满足以下两个条件的顶点 y y y 的数量:
x x x 是 y y y 的祖先;
从 x x x 到 y y y 的简单路径正好经过 i i i 条边。
顶点 x x x 的深度数组的主导索引(简称为顶点 x x x 的主导索引)是一个索引 j j j,满足:对于每个 k < j k < j k<j, d x , k < d x , j d_{x, k} < d_{x, j} dx,k<dx,j;
对于每个 k > j k > j k>j, d x , k ≤ d x , j d_{x, k} \le d_{x, j} dx,k≤dx,j。
对于树中的每个顶点,计算其主导索引。输入格式
第一行包含一个整数 n n n( 1 ≤ n ≤ 1 0 6 1 \le n \le 10^6 1≤n≤106),表示树的顶点数量。
接下来有 n − 1 n-1 n−1 行,每行包含两个整数 x x x 和 y y y( 1 ≤ x , y ≤ n 1 \le x, y \le n 1≤x,y≤n, x ≠ y x \ne y x=y),表示树中的一条边。
保证这些边构成一棵树。
输出格式
输出 n n n 个数字,第 i i i 个数字表示顶点 i i i 的主导索引
样例 #1
样例输入 #1
4 1 2 2 3 3 4
样例输出 #1
0 0 0 0
样例 #2
样例输入 #2
4 1 2 1 3 1 4
样例输出 #2
1 0 0 0
样例 #3
样例输入 #3
4 1 2 2 3 2 4
样例输出 #3
2 1 0 0
长链剖分模板题,但是用线段树合并。
这道题长链剖分没看出来,线段树合并一眼!
简单的说,我们要找每个点子树内最厚的深度(哪个深度有最多的点,这里的深度指以该点为根的深度),如果有多个答案,选择最浅的深度作为答案。
我们考虑对于每个点,将每个点的深度加入到该点的权值线段树上,然后将子树的线段树合并到该节点,最后全局查询最左的最大深度。
没什么多说的,上代码。
#include<bits/stdc++.h>
using namespace std;
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
const int N = 1e6+5;
int n,dep[N],a[N];
int head[N],nxt[N<<1],to[N<<1],cnt;
void init() {memset(head,-1,sizeof(head));cnt = 0;}
void add(int u,int v) {
nxt[cnt] = head[u];
to[cnt] = v;
head[u] = cnt++;
}
int rt[N];
namespace sgt{
int mx[N * 25],ls[N * 25],rs[N * 25],tot;
#define mid ((pl + pr) >> 1)
void push_up(int p) {mx[p] = max(mx[ls[p]],mx[rs[p]]);}
void update(int &p,int pl,int pr,int k) {
if(!p) p = ++tot;
if(pl == pr) {mx[p]++;return;}
if(k <= mid) update(ls[p],pl,mid,k);
else update(rs[p],mid+1,pr,k);
push_up(p);
}
int query(int p,int pl,int pr) {
if(!p) return 0;
if(pl == pr) return pl;
if(mx[ls[p]] >= mx[rs[p]]) return query(ls[p],pl,mid);
else return query(rs[p],mid + 1,pr);
}
int merge(int x,int y,int pl,int pr) {
if(!x || !y) return x + y;
if(pl == pr) {
mx[x] += mx[y];
return x;
}
ls[x] = merge(ls[x],ls[y],pl,mid);
rs[x] = merge(rs[x],rs[y],mid+1,pr);
push_up(x);
return x;
}
}
void dfs(int x,int f) {
dep[x] = dep[f] + 1;
for(int i = head[x];~i;i = nxt[i]) {
int y = to[i];
if(y ^ f) {
dfs(y,x);
rt[x] = sgt::merge(rt[x],rt[y],1,n);
}
}
sgt::update(rt[x],1,n,dep[x]);
a[x] = sgt::query(rt[x],1,n) - dep[x];
}
signed main() {
init();
n = rd();
for(int i = 1;i<n;i++) {
int u = rd(),v = rd();
add(u,v);add(v,u);
}
dfs(1,0);
for(int i = 1;i<=n;i++) wt(a[i]),putchar('\n');
return 0;
}