60分线段树合并代码,小数据对拍无误。
代码如下:
#include<iostream>
#include<vector>
using namespace std;
const int Z=100000;
int n,m;
vector<vector<int>> a;
int deep[100005],f[20][100005],*fa=f[0],size[100005];
int dfs1(int u) {
size[u]=1;
deep[u]=deep[fa[u]]+1;
for(auto&v:a[u]) {
if(v==fa[u]) continue;
fa[v]=u;
size[u]+=dfs1(v);
}
return size[u];
}
int LCA(int x,int y) {
if(deep[x]<deep[y]) swap(x,y);
for(int k=19;k>=0;k--)
if(deep[f[k][x]]>=deep[y])
x=f[k][x];
if(x==y) return x;
for(int k=19;k>=0;k--)
if(f[k][x]^f[k][y])
x=f[k][x],
y=f[k][y];
return fa[x];
}
struct node {
int l,r;
pair<int,int> v;//最大值权值,最大值的最小编号的相反数
int lc,rc;
}t[100010*55];//注意空间
int cnt;
int newn(int u,bool flag) {//newnode
int mid=t[u].l+t[u].r>>1;
if(!flag)//左儿子
t[t[u].lc=++cnt]={t[u].l,mid,{0,-t[u].l},0,0};//最大值编号先为左端点
else
t[t[u].rc=++cnt]={mid+1,t[u].r,{0,-mid-1},0,0};
return cnt;
}
void push_up(int u) {
if(t[u].lc) t[u].v=max(t[u].v,t[t[u].lc].v);
if(t[u].rc) t[u].v=max(t[u].v,t[t[u].rc].v);
}
void push(int u,int p,int v) {
if(t[u].l==t[u].r&&t[u].l==p) t[u].v.first+=v;
else {
int mid=t[u].l+t[u].r>>1;
if(p<=mid)
if(t[u].lc) push(t[u].lc,p,v);
else push(newn(u,0),p,v);
else
if(t[u].rc) push(t[u].rc,p,v);
else push(newn(u,1),p,v);
push_up(u);
}
}
pair<int,int> find(int u,int l,int r) {
if(l<=t[u].l&&t[u].r<=r)
return t[u].v;
int mid=t[u].l+t[u].r>>1;
pair<int,int> ans={-1e9,-1e9};
if(l<=mid&&t[u].lc)
ans=max(ans,find(t[u].lc,l,r));
if(mid<r&&t[u].rc)
ans=max(ans,find(t[u].rc,l,r));
return ans;
}
void merge(int u1,int u2) {
//u1<-u2
if(t[u1].lc&&t[u1].rc) {
if(t[u2].lc) merge(t[u1].lc,t[u2].lc);
if(t[u2].rc) merge(t[u1].rc,t[u2].rc);
}
else {
if(t[u1].lc&&t[u2].lc) merge(t[u1].lc,t[u2].lc);
if(!t[u1].lc) t[u1].lc=t[u2].lc;
if(t[u1].rc&&t[u2].rc) merge(t[u1].rc,t[u2].rc);
if(!t[u1].rc) t[u1].rc=t[u2].rc;
if(!t[u1].lc&&!t[u1].rc)
t[u1].v.first+=t[u2].v.first;
}
push_up(u1);
}
int ans[100005];
void dfs2(int u) {
for(auto&v:a[u])
if(v^fa[u])
dfs2(v),merge(u,v);
ans[u]=-find(u,1,Z).second;
}
int main() {
cin>>n>>m;
a.resize(n+1);
for(int i=1;i<n;i++) {
int u,v;
cin>>u>>v;
a[u].push_back(v);
a[v].push_back(u);
}
dfs1(1);
// for(int i=1;i<=n;i++)
// cout<<fa[i]<<' ';
// cout<<endl;
for(int k=1;k<20;k++)
for(int i=1;i<=n;i++)
f[k][i]=f[k-1][f[k-1][i]];
for(int i=1;i<=n;i++)//前n个节点必然是根节点
t[i]={1,Z,{0,0},0,0};
cnt=n;
while(m--) {
int x,y,z;
cin>>x>>y>>z;
int lca=LCA(x,y);
push(x,z,1);
push(y,z,1);
push(lca,z,-1);
if(fa[lca]) push(fa[lca],z,-1);
}
dfs2(1);
for(int i=1;i<=n;i++)
cout<<ans[i]<<endl;
return 0;
}
附送数据生成:
#include<bits/stdc++.h>
using namespace std;
int cnt,fa[100015];
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
int random(int x,int y) {
return rand()%(y-x+1)+x;
}
const int n=10,m=10;
bool vis[m+1];
int main()
{
srand(time(0));
cout<<n<<' '<<m<<endl;
for(int i=1;i<=n;i++)fa[i]=i;
while(cnt<n-1){
int x=rand()%n+1,y=rand()%n+1;
int x1=find(x),y1=find(y);
if(x1!=y1) fa[x1]=y1,cnt++,cout<<x<<" "<<y<<endl;
}
for(int i=1;i<=m;i++)
cout<<random(1,n)<<' '<<random(1,n)<<' '<<random(1,100000)<<endl;
}
(虽然z跑不满)
STO