线段树合并
前置知识:权值线段树,动态开点;
其实动态开点就是当前节点的左右子区间的节点编号不是单纯的2倍和2倍加1的关系;
我们需要存储一下左右子区间的节点编号,就可以了;
线段树合并,顾名思义,就是,将两颗值域相同权值线段树合并为一棵线段树,并且对于相同节点
相加的一些操作,具体在代码中讲解;
模板题
雨天的尾巴
#include<iostream>
#include<cstdio>
#define l(o) (t[o].ls)
#define r(o) (t[o].rs)
#define mid ((l+r)>>1)
using namespace std;
const int N=1e5+7;
const int M=1e5;
struct edge{
int v,nxt;
}e[N<<1];
struct Setment{
int ls,rs,dat,id;
}t[N*20*4];//注意线段树大小是不确定的,一般开这么多
int n,m,cnt,tot;
int head[N],dep[N],top[N],siz[N],hs[N],fa[N],ans[N],rt[N];
void add_edge(int u,int v){
e[++cnt]=(edge){v,head[u]};
head[u]=cnt;
}
void get_tree(int u){
dep[u]=dep[fa[u]]+1;
siz[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].v;
if(to!=fa[u]){
fa[to]=u;
get_tree(to);
siz[u]+=siz[to];
if(siz[hs[u]]<siz[to]) hs[u]=to;
}
}
}
void dfs(int u,int fat){
top[u]=fat;
if(hs[u]) dfs(hs[u],fat);
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].v;
if(to!=fa[u]&&to!=hs[u]){
dfs(to,to);
}
}
}
int lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
//以上为求lca操作
void up(int o){
t[o].dat=max(t[l(o)].dat,t[r(o)].dat);
t[o].id=t[o].dat==t[l(o)].dat?t[l(o)].id:t[r(o)].id;//尽量选小的
}
void insert(int &o,int l,int r,int k,int val){
if(!o) o=++tot;//动态开点,注意这里的取地址符号,是为了把编号存下来
if(l==r){
t[o].dat+=val;
t[o].id=k;
return;
}
if(k<=mid) insert(l(o),l,mid,k,val);
if(k>mid) insert(r(o),mid+1,r,k,val);
up(o);
}
void merge(int &x,int y,int l,int r){
if(!x) {
x=y;
return;
}
if(!y) return;
if(l==r){
t[x].dat+=t[y].dat;
return;
}
merge(t[x].ls,t[y].ls,l,mid);
merge(t[x].rs,t[y].rs,mid+1,r);
up(x);
}
void get_ans(int u){
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].v;
if(to!=fa[u]){
get_ans(to);
merge(rt[u],rt[to],1,M);
}
}
ans[u]=t[rt[u]].id;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add_edge(x,y);
add_edge(y,x);
}
get_tree(1);
dfs(1,1);
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
// cout<<"ffff"<<"
";
int ff=lca(x,y);
// cout<<"kkkkk"<<"
";
insert(rt[x],0,M,z,1);//rt[]数组表示为以x为根节点的线段树的最大区间;
insert(rt[y],0,M,z,1);
insert(rt[ff],0,M,z,-1);
insert(rt[fa[ff]],0,M,z,-1);//点差分
}
get_ans(1);
for(int i=1;i<=n;i++) cout<<ans[i]<<"
";
}
/*
10 10
2 1
3 2
4 3
5 3
6 3
7 4
8 5
9 8
10 3
6 2 6
3 2 6
3 3 2
6 6 6
10 3 3
10 7 1
3 7 4
7 9 5
4 2 4
3 3 6
0
6
6
4
5
6
1
5
5
1
*/