【题目】
Description
有 n n n 座城市, m m m 个民族。这些城市之间由 n − 1 n-1 n−1 条道路连接形成了以城市 1 1 1 为根的有根树。
每个城市都是某一民族的聚居地,Master 知道第 i i i 个城市的民族是 a i a_i ai,人数是 b i b_i bi。
为了维护稳定,Master 需要知道某个区域内人数最多的民族。他向你提出 n n n 个询问,其中第 i i i 个询问是:求以 i i i 为根的子树内,人数最多的民族有是哪个,这个民族有多少人。
如果子树内人数最多的民族有多个,输出其中编号最小的民族。
Input
共有
2
×
n
2\times n
2×n 行。
第一行有两个整数
n
,
m
n, m
n,m。
接下来
n
−
1
n-1
n−1 行,每行有两个整数
u
,
v
u, v
u,v,表示一条连接
u
u
u 和
v
v
v 的道路。
接下来
n
n
n 行,第
i
i
i 行有两个整数
a
i
,
b
i
a_i, b_i
ai,bi。
n
≤
400000
n\le400000
n≤400000,
m
≤
n
m\le n
m≤n,
1
≤
a
i
≤
m
1\le a_i\le m
1≤ai≤m,
0
≤
b
i
≤
1000
0\le b_i \le 1000
0≤bi≤1000。
Output
共有 n n n 行,第 i i i 行两个整数 x , y x, y x,y,分别表示以 i i i 为根的子树中人数最多的民族和它的人数。
Sample Input
8 6
1 2
1 3
2 4
4 5
3 6
5 7
1 8
2 8
2 5
1 1
3 1
6 7
5 6
1 10
4 6
Sample Output
2 13
1 10
5 6
1 10
1 10
5 6
1 10
4 6
【分析】
线段树合并的基础题
先对每个城市以建一颗线段树,树上的节点记录一个二元组(最大人数,最大人数所在的民族)
那么就从下往上合并,并记录下答案
可以用 p a i r pair pair 来简化代码,由于 p a i r pair pair 比较大小是先按照 f i r s t first first,后按照 s e c o n d second second,所以一开始把 s e c o n d second second 设为负值时,在有多个民族人数相等时,民族(也就是 − s e c o n d -second −second)中最小的会更大一点
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500005
using namespace std;
int n,m,t=0,tot=0;
int root[N],lc[N<<5],rc[N<<5];
int first[N],v[N<<1],nxt[N<<1];
pair<int,int>ans[N],Max[N<<5];
void add(int x,int y)
{
t++;
nxt[t]=first[x];
first[x]=t;
v[t]=y;
}
void insert(int &root,int l,int r,int pos,int num)
{
root=++tot;
Max[root]=make_pair(num,-pos);
if(l==r) return;
int mid=(l+r)>>1;
if(pos<=mid) insert(lc[root],l,mid,pos,num);
else insert(rc[root],mid+1,r,pos,num);
}
int Merge(int x,int y,int l,int r)
{
if(!x) return y;
if(!y) return x;
int mid=(l+r)>>1;
if(l==r) return Max[x].first+=Max[y].first,x;
lc[x]=Merge(lc[x],lc[y],l,mid);
rc[x]=Merge(rc[x],rc[y],mid+1,r);
Max[x]=max(Max[lc[x]],Max[rc[x]]);
return x;
}
void dfs(int x,int father)
{
int i,k;
for(i=first[x];i;i=nxt[i])
{
k=v[i];
if(k!=father)
{
dfs(k,x);
root[x]=Merge(root[x],root[k],1,m);
}
}
ans[x]=Max[root[x]];
}
int main()
{
int x,y,i;
scanf("%d%d",&n,&m);
for(i=1;i<n;++i)
{
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
for(i=1;i<=n;++i)
{
scanf("%d%d",&x,&y);
insert(root[i],1,m,x,y);
}
dfs(1,0);
for(i=1;i<=n;++i)
printf("%d %d\n",-ans[i].second,ans[i].first);
return 0;
}