分析:
又是一道本校OI组交流的(水)题,正解好像是线段树合并什么的,不过我用我的方法写了一下。
做过了天天爱跑步,这道题就非常简单了。
树链剖分后通过树剖dfs序模拟一遍dfs统计答案,统计时要用到一棵权值线段树。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
inline int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
}
const int MAXN=100005;
int n,m,ecnt,head[MAXN];
int fa[MAXN],dep[MAXN],siz[MAXN],pc[MAXN],top[MAXN],id[MAXN],num[MAXN],tot;
int uu[MAXN],vv[MAXN],zz[MAXN],b[MAXN],Flect[MAXN];
int loc,k;
int ans[MAXN];
std::vector<int> v[MAXN],v1[MAXN],v2[MAXN];
struct Edge{
int to,nxt;
}e[MAXN<<1];
struct Node{
int z,maxn;
}a[MAXN<<2];
inline Node max(Node x,Node y){
return x.maxn==y.maxn?(x.z<y.z?x:y):(x.maxn>y.maxn?x:y);
}
inline void add_edge(int bg,int ed){
ecnt++;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
head[bg]=ecnt;
}
void dfs1(int x,int pre,int depth){
fa[x]=pre;
dep[x]=depth;
siz[x]=1;
int maxsiz=-1;
for(int i=head[x];i;i=e[i].nxt){
int ver=e[i].to;
if(ver==pre) continue;
dfs1(ver,x,depth+1);
siz[x]+=siz[ver];
if(siz[ver]>maxsiz){
maxsiz=siz[ver];
pc[x]=ver;
}
}
}
void dfs2(int x,int topf){
top[x]=topf;
id[x]=++tot;
num[tot]=x;
if(!pc[x]) return;
v[x].push_back(pc[x]);
dfs2(pc[x],topf);
for(int i=head[x];i;i=e[i].nxt){
int ver=e[i].to;
if(ver==fa[x]||ver==pc[x]) continue;
v[x].push_back(ver);
dfs2(ver,ver);
}
}
inline int lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
inline int FindSubtree(int x,int y){
int l=0,r=v[x].size()-1;
while(l<=r){
int mid=((l+r)>>1);
if(id[v[x][mid]]>id[y]) r=mid-1;
else if(id[v[x][mid]]+siz[v[x][mid]]-1<id[y]) l=mid+1;
else return v[x][mid];
}
}
inline void AddTag(int x,int y,int z){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
v1[id[top[x]]].push_back(z);
v2[id[x]+1].push_back(z);
x=fa[top[x]];
}
if(dep[x]>dep[y]) std::swap(x,y);
v1[id[x]].push_back(z);
v2[id[y]+1].push_back(z);
}
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
void Build(int o,int l,int r){
if(l==r){
a[o].z=l;
a[o].maxn=0;
return;
}
Build(lc,l,mid);
Build(rc,mid+1,r);
a[o]=max(a[lc],a[rc]);
}
void Upd(int o,int l,int r){
if(l==r&&l==loc){
a[o].maxn+=k;
return;
}
if(loc<=mid) Upd(lc,l,mid);
else Upd(rc,mid+1,r);
a[o]=max(a[lc],a[rc]);
}
#undef mid
#undef lc
#undef rc
int main(){
n=read(),m=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
add_edge(u,v);
add_edge(v,u);
}
dfs1(1,0,1);
dfs2(1,1);
for(int i=1;i<=m;i++){
uu[i]=read();
vv[i]=read();
b[i]=zz[i]=read();
}
std::sort(b+1,b+m+1);
int ValSiz=std::unique(b+1,b+m+1)-b-1;
for(int i=1;i<=m;i++){
int temp=zz[i];
zz[i]=std::lower_bound(b+1,b+ValSiz+1,zz[i])-b;
Flect[zz[i]]=temp;
int _lca=lca(uu[i],vv[i]);
if(_lca==vv[i]) AddTag(_lca,uu[i],zz[i]);
else if(_lca==uu[i]) AddTag(_lca,vv[i],zz[i]);
else{
int temp=FindSubtree(_lca,vv[i]);
AddTag(_lca,uu[i],zz[i]);
AddTag(temp,vv[i],zz[i]);
}
}
Build(1,1,ValSiz);
for(int i=1;i<=n;i++){
for(int j=0;j<v1[i].size();j++){
loc=v1[i][j];k=1;
Upd(1,1,ValSiz);
}
for(int j=0;j<v2[i].size();j++){
loc=v2[i][j];k=-1;
Upd(1,1,ValSiz);
}
ans[num[i]]=Flect[a[1].z];
if(!a[1].maxn) ans[num[i]]=0;
}
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
return 0;
}