Description
深绘里一直很讨厌雨天。
灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。
虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连
根拔起,以及田地里的粮食被弄得一片狼藉。
无奈的深绘里和村民们只好等待救济粮来维生。
不过救济粮的发放方式很特别。
首先村落里的一共有n 座房屋,并形成一个树状结构。然后救济粮分m 次发放,每次选择
两个房屋(x,y),然后对于x 到y 的路径上(含x 和y) 每座房子里发放一袋z 类型的救济粮。
然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。
Solution
首先所有的操作是已经给定的,询问都是固定的。
我们考虑在序列上做覆盖,在左右端点加1减1,维护最大值即可。
如果在树上,那我们先把树剖成一条条链,再在上面做覆盖即可。时间复杂度O( nlog22 )
可不可以不这么麻烦呢?我们直接考虑树上覆盖。
显然,在左端点
x
+1,右端点
于是我们动态开一棵权值线段树,维护每个点最大值的编号。
操作完成后,对于原图每个节点,我们把它与儿子节点合并线段树,对于这题来说,合并就是把个数加起来即可。
这样合并一次是
log2m
,
n
次合并就是
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 100001
#define M 200001
#define mo 200007
using namespace std;
int to[M],next[M],last[M],num=0;
int d[N],f[N][21];
struct node{
int l,r;
int mx;
}tr[N*50];
int a[N];
int h[mo];
int b[N];
int tot=0;
int hash(int x)
{
int p=x%mo;
while(h[p] && h[p]!=x) p=(p+1)%mo;
h[p]=x;
return p;
}
void link(int x,int y)
{
num++;
to[num]=y;
next[num]=last[x];
last[x]=num;
}
int cnt=0;
void find(int x)
{
for(int i=last[x];i;i=next[i])
{
int v=to[i];
if(v!=f[x][0])
{
f[v][0]=x;
d[v]=d[x]+1;
find(v);
}
}
}
int lca(int x,int y)
{
int tmp=0;
if(d[x]>d[y]) swap(x,y);
fd(i,14,0)
while(d[f[y][i]]>=d[x]) y=f[y][i];
fd(i,14,0)
while(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
if(x!=y) x=f[x][0],y=f[y][0];
return x;
}
void change(int v,int l,int r,int x,int p)
{
if(l==r && l==x)
{
tr[v].mx+=p;
return;
}
int mid=(l+r)/2;
if(x<=mid)
{
if(!tr[v].l) tr[v].l=++tot;
change(tr[v].l,l,mid,x,p);
}
else
{
if(!tr[v].r) tr[v].r=++tot;
change(tr[v].r,mid+1,r,x,p);
}
int i=tr[v].l,j=tr[v].r;
tr[v].mx=max((!i?0:tr[i].mx),(!j?0:tr[j].mx));
}
void merge(int v,int vv,int l,int r)
{
if(l==r)
{
tr[v].mx+=tr[vv].mx;
return;
}
int mid=(l+r)/2;
if(tr[vv].l)
{
if(!tr[v].l) tr[v].l=tr[vv].l;
else merge(tr[v].l,tr[vv].l,l,mid);
}
if(tr[vv].r)
{
if(!tr[v].r) tr[v].r=tr[vv].r;
else merge(tr[v].r,tr[vv].r,mid+1,r);
}
int i=tr[v].l,j=tr[v].r;
tr[v].mx=max((!i?0:tr[i].mx),(!j?0:tr[j].mx));
}
int findans(int v,int l,int r)
{
if(l==r) return l;
int mid=(l+r)/2;
int i=tr[v].l,j=tr[v].r;
if(tr[i].mx>=tr[j].mx) findans(i,l,mid);
else findans(j,mid+1,r);
}
int lyd=0;
void dfs(int x)
{
for(int i=last[x];i;i=next[i])
{
int v=to[i];
if(v!=f[x][0])
{
dfs(v);
merge(a[x],a[v],1,mo-1);
}
}
b[x]=findans(a[x],1,mo-1);
}
int main()
{
int n,m;
cin>>n>>m;
fo(i,1,n-1)
{
int x,y;
scanf("%d %d",&x,&y);
link(x,y);
link(y,x);
}
find(1);
fo(j,1,20)
fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1];
fo(i,1,n) a[i]=i;
tot=n;
d[0]=-1;
fo(i,1,m)
{
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
int p=hash(z);
change(a[x],1,mo-1,z,1);
change(a[y],1,mo-1,z,1);
int t=lca(x,y);
change(a[t],1,mo-1,z,-1);
change(a[f[t][0]],1,mo-1,z,-1);
}
dfs(1);
fo(i,1,n) printf("%d\n",h[b[i]]);
}