题目链接
题意:
给定一颗n个结点的树,进行m次染色操作,对于每一次染色操作是选择树上的一条路径,将路径上所有节点都染上第 z z z种颜色。
输出m次操作以后,每一个节点上染色次数最多的颜色。
1 < = n , m , z < = 1 e 5 1<=n,m,z <= 1e5 1<=n,m,z<=1e5
思路:
对于树上的路径操作,自然能够想到使用树链剖分,将树形结构转化为线形结构,并能够将树上的路径划分为几个连续的区间。
随后问题转化为:
在一个一维数轴上,进行m次染色,每次选择一个区间染成某一种颜色,问最后每一个点染色次数最多的颜色。
对于该问题,我们首先考虑一个简单的版本,即只存在一种颜色,我们如何求出该颜色在每一个点的染色次数呢?
考虑扫描线,即对于每一个区间 [ L , R ] [L,R] [L,R],我们在 L L L处加1, R + 1 R+1 R+1处减 1 1 1,最后扫一遍即可。
那对于多种颜色,虽然计算还是+1或者-1的计算,但为了区分不同的颜色,对于颜色 k k k,我们标记时使用 + k +k +k或 − k -k −k。
此时对于该题我们就有了清晰的思路,首先对于每一个点开一个vector,用于保存该点的标记。
随后对于每一次染色,使用树链剖分将路径转化为几个连续的区间,对于区间 [ L , R ] [L,R] [L,R]染第 k k k种颜色,我们就更新:
vector<int> vec[n+1];
for x in All_Segment:
vec[x.L].push_back(x.k);
vec[x.R].push_back(-x.k);
定义数组:Ans[i]:第i种节点当前的染色次数
按顺序遍历节点,随后遍历其对应的vector,更新Ans数组。
随后从Ans数组里面找出值最大且序号最小的下标即可。
这一步可以使用权值线段树进行优化。
此题得解。
代码:
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define lson rt<<1
#define rson rt<<1|1
const int A = 1e5 + 10;
class Gra{
public:
int v,next;
}G[A<<2];
class Seg_Tree{
public:
int l,r,Mx;
}Tree[A<<2];
int n,m,head[A],tot,twt;
int fa[A],dep[A],siz[A],son[A],top[A],pos[A],ID[A],Ans[A];
vector<int> v[A];
void init(){
for(int i=0 ;i<A ;i++){
v[i].clear();
head[i] = -1;
}
siz[0] = 0;
tot = twt = 0;
}
void add(int u,int v){
G[tot].v = v;
G[tot].next = head[u];
head[u] = tot++;
}
void dfs(int u,int pre,int d){
fa[u] = pre;son[u] = -1;
siz[u] = 1;dep[u] = d;
for(int i=head[u] ; i!=-1 ;i=G[i].next){
int v = G[i].v;
if(v == pre) continue;
dfs(v,u,d+1);
siz[u] += siz[v];
if(son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs(int u,int tp){
pos[u] = ++twt;
ID[twt] = u;
top[u] = tp;
if(son[u] == -1) return;
dfs(son[u],tp);
for(int i=head[u] ; i!=-1 ;i=G[i].next){
int v = G[i].v;
if(v == son[u] || v == fa[u]) continue;
dfs(v,v);
}
}
void Calc(int x,int y,int c){
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x,y);
v[pos[top[x]]].push_back(c);
v[pos[x]+1].push_back(-c);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x,y);
v[pos[x]].push_back(c);
v[pos[y]+1].push_back(-c);
}
void push_up(int rt){
Tree[rt].Mx = max(Tree[lson].Mx,Tree[rson].Mx);
}
void build_Tree(int rt,int l,int r){
Tree[rt].l = l;Tree[rt].r = r;
Tree[rt].Mx = 0;
if(l == r) return;
int mid = (l+r)>>1;
build_Tree(lson,l,mid);
build_Tree(rson,mid+1,r);
push_up(rt);
}
void update(int rt,int pos,int c){
int l = Tree[rt].l,r = Tree[rt].r;
if(l == r){
Tree[rt].Mx += c;
return;
}
int mid = (l+r)>>1;
if(pos <= mid) update(lson,pos,c);
else update(rson,pos,c);
push_up(rt);
}
int query(int rt,int Mx){
int l = Tree[rt].l,r = Tree[rt].r;
if(l == r) return l;
if(Tree[lson].Mx == Mx) return query(lson,Mx);
else return query(rson,Mx);
}
int main(){
while(~scanf("%d%d",&n,&m)){
if(n == 0 && m == 0) break;
init();
for(int i=1 ;i<n ;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
dfs(1,1,1);
dfs(1,1);
int Mx = 0;
for(int i=1 ;i<=m ;i++){
int st,ed,col;
scanf("%d%d%d",&st,&ed,&col);
Calc(st,ed,col);
Mx = max(Mx,col);
}
build_Tree(1,1,A);
for(int i=1 ;i<=n ;i++){
int Siz = v[i].size();
for(int j=0 ;j<Siz ;j++){
if(v[i][j] > 0) update(1,v[i][j],1);
else update(1,-v[i][j],-1);
}
if(Tree[1].Mx == 0) Ans[ID[i]] = 0;
else Ans[ID[i]] = query(1,Tree[1].Mx);
}
for(int i=1 ;i<=n ;i++){
printf("%d\n",Ans[i]);
}
}
return 0;
}