求今年NOIP靠树上启发式合并qaq。
https://www.luogu.com.cn/problem/P4556
正解(大概)线段树合并。
考虑类似扫描线式地树上差分。求贡献考虑使用树上启发式合并+set来维护。
d[x] += 1, d[y] += 1, d[lca] -= 1, d[fa(lca)] -= 1
d[x] += 1, d[y] += 1, d[lca] -= 2
优秀的细节
删点贡献和加点贡献考虑使用dfn便历法代替dfs。
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N = 1e5+11 ;
int f[N][20],dep[N],ans[N],son[N];
int sz[N],L[N],R[N],dfn[N],Node[N],tot,cnt[N];
vector<int> g[N],ad[N],de[N];
struct kkk{
int id,v;
bool operator < (const kkk a)const{
if(a.v == v)return id<a.id;
return v>a.v;
}
};
set<kkk> s;
void init(int u,int fa){
tot++;
L[u] = tot;
Node[tot] = u;
f[u][0] = fa;
sz[u] = 1;
dep[u] = dep[fa]+1;
for(int i = 1;i <= 18;i++){
f[u][i] = f[f[u][i-1]][i-1];
}
for(int v:g[u]){
if(v == fa)continue;
init(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]){
son[u]=v;
}
}
R[u] = tot;
}
int lca(int u,int v){
if(dep[v]>dep[u])swap(u,v);
for(int i = 18;i>=0;i--){
if(dep[f[u][i]] >= dep[v]){
u = f[u][i];
}
}
if(u == v)return v;
for(int i = 18;i >= 0;i--){
if(f[u][i]!=f[v][i]){
u = f[u][i];
v = f[v][i];
}
}
return f[u][0];
}
void add(int u) {
for(int col:ad[u]){
if(cnt[col]>0)s.erase({col,cnt[col]});
cnt[col]++;
s.insert({col,cnt[col]});
}
for(int col:de[u]){
s.erase({col,cnt[col]});
cnt[col]--;
if(cnt[col]>0)s.insert({col,cnt[col]});
}
}
void del(int u){
for(int col:ad[u]){
s.erase({col,cnt[col]});
cnt[col]--;
if(cnt[col]>0)s.insert({col,cnt[col]});
}
for(int col:de[u]){
if(cnt[col]>0)s.erase({col,cnt[col]});
cnt[col]++;
s.insert({col,cnt[col]});
}
}
void dfs(int u,int fa,bool keep){
for(int v:g[u]){
if(v == fa||v == son[u])continue;
dfs(v,u,0);
}
if(son[u]){
dfs(son[u],u, 1);
}
for(int v:g[u]){
if(v == fa||v == son[u])continue;
for (int i = L[v]; i <= R[v]; i++) {
add(Node[i]);
}
}
add(u);
ans[u] = (*s.begin()).id;
if (!keep) {
for (int i = L[u]; i <= R[u]; i++) {
del(Node[i]);
}
}
}
int main(){
ios::sync_with_stdio(0);
cin>>n>>m;
for(int i = 1;i <= n-1;i++){
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
init(1,0);
s.insert({0,0});
for(int i = 1;i <= m;i++){
int x,y,z;
cin>>x>>y>>z;
ad[x].push_back(z);
ad[y].push_back(z);
de[lca(x,y)].push_back(z);
de[f[lca(x,y)][0]].push_back(z);
//cout<<lca(x,y)<<endl;
}
dfs(1,0,0);
for(int i = 1;i <= n;i++){
cout<<ans[i]<<endl;
}
return 0;
}
150

被折叠的 条评论
为什么被折叠?



