Description
中二少年cenbo幻想自己统治着Euphoric Field。由此他开始了Endless Fantasy。
Euphoric Field有n座城市,m个民族。这些城市之间由n-1条道路连接形成了以城市1为根的有根树。每个城市都是某一民族的聚居地,cenbo知道第i个城市的民族是A_i,人数是B_i。为了维护稳定,cenbo需要知道某个区域内人数最多的民族。他向你提出n个询问,其中第i个询问是:求以i为根的子树内,人数最多的民族有是哪个,这个民族有多少人。如果子树内人数最多的民族有多个,输出其中编号最小的民族。
30%的数据,n<=1000;
60%的数据,n<=40000;
100%的数据,n<=400000,m<=n,1<=A_i<=m,0<=B_i<=1000。
输入文件较大请使用读入优化。
Solution
这是我比较顺手的一类题目
考虑离线询问。我只会两个做法,线段树合并和树上启发式合并
考虑到各种因素这里写了dsu on tree+线段树的没有梦想做法,实际可以用桶代替线段树来跑得更快
这种写法需要卡常
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define rep(i,st,ed) for (register int i=st,_=ed;i<=_;++i)
const int N=400005;
struct edge {int y,next;} e[N*2+1];
struct data {int x,y;} ans[N];
std:: vector <data> rec[N];
int size[N],son[N],fa[N];
int max[N<<2],c[N],pos[N];
int ls[N],id[N],edCnt,n,m;
inline int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
inline void swap(int &x,int &y) {
int z=x; x=y; y=z;
}
inline void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}
inline void dfs(int now) {
size[now]=1;
for (register int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa[now]) continue;
fa[e[i].y]=now; dfs(e[i].y);
size[now]+=size[e[i].y];
if (size[e[i].y]>size[son[now]]) son[now]=e[i].y;
}
}
inline void change(int x,int v) {
for (register int i=0,_=rec[id[x]].size();i<_;++i) {
data tmp=rec[id[x]][i];
c[tmp.x]+=tmp.y*v;
for (register int now=(pos[tmp.x]>>1);now;now>>=1) {
int wjp=max[now];
if (c[max[now<<1|1]]>c[max[now<<1]]) max[now]=max[now<<1|1];
else max[now]=max[now<<1];
if (wjp==max[now]&&wjp!=tmp.x) break;
}
}
}
inline void solve(int now) {
for (register int i=ls[now];i;i=e[i].next) {
if (e[i].y!=fa[now]&&e[i].y!=son[now]) {
solve(e[i].y);
change(e[i].y,-1);
}
}
if (son[now]) solve(son[now]);
for (register int i=ls[now];i;i=e[i].next) {
if (e[i].y!=fa[now]&&e[i].y!=son[now]) {
change(e[i].y,1);
}
}
change(now,1);
ans[now]=(data){max[1],c[max[1]]};
for (register int i=ls[now];i;i=e[i].next) {
if (e[i].y!=fa[now]) {
if (rec[id[now]].size()<rec[id[e[i].y]].size()) swap(id[now],id[e[i].y]);
int a=id[now],b=id[e[i].y];
for (register int j=0,_=rec[b].size();j<_;++j) {
rec[a].push_back(rec[b][j]);
}
id[e[i].y]=0;
}
}
}
inline void build(int now,int tl,int tr) {
if (tl==tr) {
pos[tl]=now;
return (void) (max[now]=tl);
}
int mid=(tl+tr)>>1;
build(now<<1,tl,mid);
build(now<<1|1,mid+1,tr);
}
int main(void) {
freopen("endless.in","r",stdin);
freopen("endless.out","w",stdout);
n=read(),m=read();
build(1,1,m);
rep(i,2,n) add_edge(read(),read());
dfs(1);
rep(i,1,n) {
rec[i].push_back((data){read(),read()});
id[i]=i;
}
solve(1);
rep(i,1,n) printf("%d %d\n", ans[i].x,ans[i].y);
return 0;
}