1. 程式人生 > 實用技巧 >[CF55D] Beautiful numbers - 數位dp

[CF55D] Beautiful numbers - 數位dp

大致題意

給一顆\(n\)個節點的樹,現在有\(m\)次操作,每次選擇兩個節點\(u\),\(v\),對\(u\)\(v\)的路徑上的每個節點都發放一袋\(z\)型別的物品

求所有操作完成後,每個點存放最多的是哪種物品

\(n,m≤10^5,z≤10^9\)

分析

線段樹合併模板題

差分+離散化一下

每次操作時將\(u\)\(v\)的權值線段樹中的\(z\)位置\(+1\),\(lca(u,v)\)\(fa_{lca(u,v)}\)中的\(z\)位置\(-1\),所有操作完成後再\(dfs\)一遍合併子樹

複雜度\((n+m)log(n+m)\)

\(code\)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100010;
int n,m;
int f[MAXN][21],dep[MAXN];

inline int read(){
	int X=0; bool flag=1; char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
	while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
	if(flag) return X;
	return ~(X-1);
}
struct st{
	int lson,rson,val,pos;
}tree[MAXN*100];
int tot,root[MAXN];
struct e{
	int v,next;
}edge[MAXN<<1];
int head[MAXN<<1],cnt;
void add(int u,int v){
	edge[++cnt].v = v;
	edge[cnt].next = head[u];
	head[u] = cnt;
}
struct Lca{
	void dfs(int u,int fa){
	dep[u] = dep[fa]+1;
	f[u][0] = fa;
	for(int i=1;(1<<i)<=dep[u];i++){
		f[u][i] = f[f[u][i-1]][i-1];
	}
	for(int i=head[u];i;i=edge[i].next){
		int v = edge[i].v;
		if(v==fa) continue;
		dfs(v,u);
	}
}
    int lca(int u,int v){
	if(dep[u]>dep[v]) swap(u,v);
	for(int i=20;i>=0;i--){
		if(dep[u]<=dep[v]-(1<<i)) v = f[v][i];
	}
	if(u==v) return u;
	for(int i=20;i>=0;i--){
		if(f[u][i]!=f[v][i]){
			u = f[u][i];
			v = f[v][i];
		}
	}
	return f[u][0];
}
}LCA;

void pushup(int node){
	tree[node].val = max(tree[tree[node].lson].val,tree[tree[node].rson].val);
	tree[node].pos = tree[tree[node].lson].val>=tree[tree[node].rson].val?tree[tree[node].lson].pos:tree[tree[node].rson].pos;
} 
void insert(int &node,int l,int r,int pos,int val){
	if(!node) node = ++tot;
	if(l==r){
		tree[node].val += val;
		tree[node].pos = l;
		return;
	}
	int mid = (l+r)>>1;
	if(pos<=mid) insert(tree[node].lson,l,mid,pos,val);
	else if(pos>mid)insert(tree[node].rson,mid+1,r,pos,val);
	pushup(node);
}
int merge(int a,int b,int l,int r){
	if(!b) return a;
	if(!a) return b;
	if(l==r){
		tree[a].val+=tree[b].val;
		tree[a].pos = tree[a].val?l:0;
		return a;
	}
	int mid = (l+r)>>1;
	tree[a].lson = merge(tree[a].lson,tree[b].lson,l,mid);
	tree[a].rson = merge(tree[a].rson,tree[b].rson,mid+1,r);
	pushup(a);
	return a; 
}
int len;
int a[MAXN],b[MAXN],c[MAXN];
int value[MAXN];
int ans[MAXN];
int getid(int x){
	return lower_bound(value+1,value+1+len,c[x]) - value;
}
void dfs2(int u,int fa){
	for(int i=head[u];i;i=edge[i].next){
		int v = edge[i].v;
		if(v==fa) continue;
		dfs2(v,u);
		merge(root[u],root[v],1,len);
	}
	ans[u] = tree[root[u]].pos;
}
int main(){
	n = read(),m = read();
	for(int i=1;i<n;i++){
		int u = read(),v = read();
		add(u,v),add(v,u);
	}
	LCA.dfs(1,0);
	for(int i=1;i<=n;i++) root[i] = ++tot; 
	for(int i=1;i<=m;i++){
		a[i] =read(),b[i] = read(),c[i] = read();
		value[i] = c[i];
	}
	sort(value+1,value+1+m);
	len = unique(value+1,value+1+m)-(value+1);
	for(int i=1;i<=m;i++){
		int x = a[i],y = b[i],z = getid(i);
		int fa = LCA.lca(x,y);
		int Fa = f[fa][0];
		insert(root[x],1,len,z,1);
		insert(root[y],1,len,z,1);
		insert(root[fa],1,len,z,-1);
		if(Fa) insert(root[Fa],1,len,z,-1);
	}
	dfs2(1,0);
	for(int i=1;i<=n;i++){
		printf("%d\n",value[ans[i]]);
	}
}