题目大意
给定一棵n个点的树。有m个操作,每个操作给出x,y,z,然后对于点x 到点y 的路径上(含x 和y) 每个点对应数值为z的数的个数+1。
最后输出每个点个数最多的数的数值(个数相同输出数值较小值)。
数据范围 n,m <= 100000,z<=10^9。
树链剖分,复杂度O( nlogn2 )
(werkeytom大神用线段树合并O(n log n)解决)
z比较大,但最多也就m种,所以我们先离散化z。
首先考虑序列上的做法,对于一个操作x,y,z(离散化后的),我们拆成两个操作
1:a=x,z,b=1;2:a=y+1,z,b=-1。然后把操作按a值排序。
然后我们O(n)扫一遍每个位置,把每个位置上的操作都处理掉,每个操作为数值为z的数的个数+b,用线段树维护数值为z的数的个数,那么当前位置的答案我们可以直接得出。修改操作复杂度为O(log n),总复杂度O(n log n)。
树上的怎么做呢?我们可以树链剖分一下,每条链都是一段序列,所以我们可以把操作拆开,一个操作最多拆log n次,然后剩下的按序列上的做,总时间O(
nlogn2
)
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=100000+5;
int tree[maxn*4],p[maxn],tr[maxn*4],t,n,m,k[maxn],c[maxn],next[maxn*2],g[maxn*2],num,s[maxn],son[maxn],b[maxn],a[maxn],qx[maxn],qy[maxn],ans[maxn],q[maxn],fa[maxn],f[maxn],d[maxn],bz[maxn],bk[maxn],cnt[maxn*36][3];
void add(int x,int y){
next[++num]=k[x];
k[x]=num;
g[num]=y;
}
void read(int &n){
char ch=getchar();
while(ch!='-'&&(ch<'0')||(ch>'9'))ch=getchar();n=0;
int q=1;if (ch=='-') ch=getchar(),q=-1;
while(ch>='0'&&ch<='9')n=n*10+ch-'0',ch=getchar();n=n*q;
}
void dfs(int x,int y){
int i=k[x],s1=0;
s[x]=1;fa[x]=y;f[x]=x;
while (i>0){
if (g[i]!=y) {
d[g[i]]=d[x]+1;
dfs(g[i],x);
s[x]+=s[g[i]];
if (s[g[i]]>s1) s1=s[g[i]],son[x]=g[i];
}
i=next[i];
}
}
void df(int x,int y){
if (son[y]==x) f[x]=f[y];
b[x]=++num;
a[num]=x;
if (son[x]>0) df(son[x],x);
int i=k[x];
while (i>0){
if (g[i]!=y&&son[x]!=g[i]) df(g[i],x);
i=next[i];
}
}
void qs(int l,int r){
int i=l,j=r,m=q[(l+r)/2];
while (i<=j){
while (q[i]<m) i++;
while (q[j]>m) j--;
if (i<=j){
swap(q[i],q[j]);
swap(qx[i],qx[j]);
swap(qy[i],qy[j]);
i++;j--;
}
}
if (i<r) qs(i,r);
if (l<j) qs(l,j);
}
void qss(int l,int r){
int i=l,j=r,m=cnt[(l+r)/2][1];
while (i<=j){
while (cnt[i][1]<m) i++;
while (cnt[j][1]>m) j--;
if (i<=j){
swap(cnt[i],cnt[j]);
i++;j--;
}
}
if (i<r) qss(i,r);
if (l<j) qss(l,j);
}
void put(int k,int l,int r,int x,int y){
if (l==r) {
tree[k]+=y;
tr[k]=p[l];
return;
}
int m=(l+r)/2;
if (x<=m) put(k*2,l,m,x,y);else
put(k*2+1,m+1,r,x,y);
if (tree[k*2]>=tree[k*2+1]) {
tree[k]=tree[k*2];
tr[k]=tr[k*2];
}else{
tree[k]=tree[k*2+1];
tr[k]=tr[k*2+1];
}
}
int main(){
read(n);read(m);num=0;
for (int i=1;i<n;i++){
int x,y;read(x);read(y);
add(x,y);add(y,x);
}
dfs(1,0);num=0;
df(1,0);
for (int i=1;i<=m;i++) read(qx[i]),read(qy[i]),read(q[i]);
qs(1,m);q[0]=0;t=0;
for (int i=1;i<=m;i++) if (q[i]>q[i-1]) c[i]=++t,p[t]=q[i];else c[i]=t;
num=0;
for (int i=1;i<=m;i++){
int x=qx[i],y=qy[i];
while (f[x]!=f[y]){
if (d[f[x]]<d[f[y]]) swap(x,y);
num++;cnt[num][0]=c[i];
cnt[num][1]=b[f[x]];cnt[num][2]=1;
num++;cnt[num][0]=c[i];
cnt[num][1]=b[x]+1;cnt[num][2]=-1;
x=fa[f[x]];
}
if (d[x]<d[y]) swap(x,y);
num++;cnt[num][0]=c[i];
cnt[num][1]=b[y];cnt[num][2]=1;
num++;cnt[num][0]=c[i];
cnt[num][1]=b[x]+1;cnt[num][2]=-1;
} qss(1,num);int j=1;
for (int i=1;i<=n;i++){
while (j<=num&&cnt[j][1]==i) put(1,1,t,cnt[j][0],cnt[j][2]),j++;
if (tree[1]>0)ans[a[i]]=tr[1];else ans[a[i]]=0;
}
for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
}