1. 程式人生 > 實用技巧 >類的繼承之發紅包的案例----Java

類的繼承之發紅包的案例----Java

gate

線段樹合併

設兩個要合併的線段樹為\(a\),\(b\)
\(a\)\(b\)不存在,則返回另一個。
否則,將\(b\)的數值累加到\(a\)上,並返回\(a\)
程式碼如下

int merge(int a,int b,int l,int r) {
	if(!a) return b;
	if(!b) return a;
	if(l == r) {
		mx[a] += mx[b];
		return a;
	}
	int mid = Mid;
	ls[a] = merge(ls[a],ls[b],l,mid);
	rs[a] = merge(rs[a],rs[b],mid+1,r);
	pushup(a);
	return a;
}

對於這道題,用線段樹維護每個房屋獲得的不同種類救濟糧的個數和最大值,
用樹上差分維護每個房屋。
\(sum[i]\)表示從\(1\)\(i\)的路徑上都增加了\(i\)個,
則對於一次增加操作\((i,j)\)
\(sum[i]+1,sum[j]+1;sum[lca(i,j)]-1,sum[fa[lca(i,j)]-1\)
從下向上合併線段樹。

code

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define MogeKo qwq
using namespace std;

#define Mid (l+r>>1)

const int maxn = 6e6+5;
const int N = 1e5;

int n,m,x,y,z,cnt,tot;
int rt[N+5],ans[N+5];
int ls[maxn],rs[maxn],mx[maxn],id[maxn];
int dpth[N+5],p[N+5][25];
int head[N+5],to[N+5<<1],nxt[N+5<<1];


void add(int x,int y) {
	to[++cnt] = y;
	nxt[cnt] = head[x];
	head[x] = cnt;
}

void get_p(int u,int fa) {
	dpth[u] = dpth[fa]+1;
	p[u][0] = fa;
	for(int i = 1; (1<<i) <= dpth[u]; i++)
		p[u][i] = p[p[u][i-1]][i-1];
	for(int i = head[u]; i; i = nxt[i]) {
		int v = to[i];
		if(v == fa) continue;
		get_p(v,u);
	}
}

int Lca(int a,int b) {
	if(dpth[a] < dpth[b]) swap(a,b);
	for(int i = 20; i >= 0; i--) {
		if(dpth[a] - (1<<i) >= dpth[b])
			a = p[a][i];
	}
	if(a == b) return a;
	for(int i = 20; i >= 0; i--)
		if(p[a][i] != p[b][i])
			a = p[a][i], b = p[b][i];
	return p[a][0];
}

void pushup(int now) {
	if(mx[ls[now]] >= mx[rs[now]]) {
		mx[now] = mx[ls[now]];
		id[now] = id[ls[now]];
	} else {
		mx[now] = mx[rs[now]];
		id[now] = id[rs[now]];
	}
}

int modify(int now,int l,int r,int x,int val) {
	if(!now) now = ++tot;
	if(l == r) {
		mx[now] += val;
		id[now] = x;
		return now;
	}
	int mid = Mid;
	if(x <= mid) ls[now] = modify(ls[now],l,mid,x,val);
	else rs[now] = modify(rs[now],mid+1,r,x,val);
	pushup(now);
	return now;
}

int merge(int a,int b,int l,int r) {
	if(!a) return b;
	if(!b) return a;
	if(l == r) {
		mx[a] += mx[b];
		return a;
	}
	int mid = Mid;
	ls[a] = merge(ls[a],ls[b],l,mid);
	rs[a] = merge(rs[a],rs[b],mid+1,r);
	pushup(a);
	return a;
}

void dfs(int u,int fa) {
	for(int i = head[u]; i; i = nxt[i]) {
		int v = to[i];
		if(v == fa) continue;
		dfs(v,u);
		rt[u] = merge(rt[u],rt[v],1,N);
	}
	if(mx[rt[u]]) ans[u] = id[rt[u]];
}

int main() {
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n-1; i++) {
		scanf("%d%d",&x,&y);
		add(x,y), add(y,x);
	}
	get_p(1,0);
	for(int i = 1; i <= m; i++) {
		scanf("%d%d%d",&x,&y,&z);
		int f = Lca(x,y);
		int ff = p[f][0];
		rt[x] = modify(rt[x],1,N,z,1);
		rt[y] = modify(rt[y],1,N,z,1);
		rt[f] = modify(rt[f],1,N,z,-1);
		if(ff) rt[ff] = modify(rt[ff],1,N,z,-1);
	}
	dfs(1,0);
	for(int i = 1; i <= n; i++)
		printf("%d\n",ans[i]);
	return 0;
}