【NOIP模拟题】【线段树】【树链剖分】发放粮食题解

发放粮食
描述
有一个村庄在闹饥荒,善良而土豪的YGH决定给他们发放救济粮,该村庄有 n 户人家,每两户人家之间只有一条路可以互相到达,即这些人家之间形成一棵树。现在 YGH 会以这样的形式给他们发放粮食,选择两户人家,然后对这两个户人家路径上的所有人家都发放一袋种类为 w 的救济粮。在完成一系列发放任务后,YGH 想知道每一户人家收到的粮食中数量最多的是哪一种。
输入
第一行两个数 n,q,其中 n 表示村庄共有几户人家,q 表示 YGH 一共发放了几次粮食。接下来 n-1 行,每行两个数 x y,表示编号为 x 和 y 的两户人家之间连有边。接下来 q 行,每行三个数 x y w,表示 YGH 选择了 x 到 y 的路径,对每户人家发放 1 袋种类为 w 的粮食。
输出
输出 n 行,第 i 行输出编号为 i 的人家收到的粮食中数量最多的种类号,如果有多个数量相同的粮食,输出其中最小的种类号,如果没有收到粮食,输出0
样例输入
[1]
2 4
1 2
1 1 1
1 2 2
2 2 2
2 2 1
[2]
5 3
1 2
3 1
3 4
5 3
2 3 3
1 5 2
3 3 3
样例输出
[1]
1
2
[2]
2
3
3
0
2
提示
对于 40% 的数据 n<=1000,q<=1000,1<=w<=1000

对于 100% 的数据 n<=100000,q<=100000,1<=w<=100000 1<=x,y<=n

这道题我们可以用树链剖分搞它,也可以将每个点建立一个线段树。但如果见那么多线段树就会MLE就GG了,所以我们用启发式合并来优化,但还是不够,所以我们再节约点内存用个队列。

作为一个高一的菜鸟就不把我的暴力程序给出来了,附某大大的代码

#include <cstdio>
#include <cstring>
#include <vector>
#define lson rt<<1
#define rson rt<<1|1
#define maxn 100010

using namespace std;

struct Pair {
	int ind, val;
	Pair(){}
	Pair( int ii, int vv ) : ind(ii), val(vv) {}
};

int n, q;
vector<int> g[maxn], flag[maxn];
int siz[maxn], son[maxn], dep[maxn], pre[maxn], top[maxn], vid[maxn], id_clock;
int maxw, ans[maxn];
Pair seg[maxn<<2]; 

void input() {
	scanf( "%d%d", &n, &q );
	for( int i=1,u,v; i<n; i++ ) {
		scanf( "%d%d", &u, &v );
		g[u].push_back(v);
		g[v].push_back(u);
	}
}

void update( int w, int delta, int rt, int l, int r ) {
	if( l==r ) {
		seg[rt].val += delta;
		seg[rt].ind = l;
		return;
	}
	int mid = (l+r)>>1;
	if( mid>=w ) update( w, delta, lson, l, mid );
	else update( w, delta, rson, mid+1, r );
	seg[rt] = seg[lson].val < seg[rson].val ? seg[rson] : seg[lson];
}

void dfs1( int u ) {
	siz[u] = 1, son[u] = 0;
	for( int t=0; t<(int)g[u].size(); t++ ) {
		int v=g[u][t];
		if( v==pre[u] ) continue;
		dep[v] = dep[u]+1;
		pre[v] = u;
		dfs1(v);
		siz[u] += siz[v];
		son[u] = siz[v]>siz[son[u]] ? v : son[u];
	}
}

void dfs2( int u, int tp ) {
	top[u] = tp, vid[u] = ++id_clock;
	if( son[u] ) dfs2( son[u], tp );
	for( int t=0; t<(int)g[u].size(); t++ ) {
		int v=g[u][t];
		if( v==pre[u] || v==son[u] ) continue;
		dfs2( v, v );
	}
}

void build() {
	dep[1] = pre[1] = 1;
	dfs1(1);
	id_clock = 0;
	dfs2(1,1);
}

void modify( int u, int v, int w ) {
	while( top[u] != top[v] ) {
		if( dep[top[u]]<dep[top[v]] ) swap(u,v);
		flag[vid[top[u]]].push_back(w);
		flag[vid[u]+1].push_back(-w);
		u = pre[top[u]];
	}
	if( dep[u]<dep[v] ) swap(u,v);
	flag[vid[v]].push_back(w);
	flag[vid[u]+1].push_back(-w);
}

void answer() {
	for( int i=1; i<=q; i++ ) {
		int u, v, w;
		scanf( "%d%d%d", &u, &v, &w );
		modify( u, v, w );
		maxw = max( maxw, w );
	}
	for( int i=1; i<=id_clock; i++ ) {
		for( int t=0; t<(int)flag[i].size(); t++ ) {
			if( flag[i][t]>0 ) update( flag[i][t], 1, 1, 1, maxw );
			if( flag[i][t]<0 ) update( -flag[i][t], -1, 1, 1, maxw );
		}
		if( seg[1].val==0 ) ans[i] = 0;
		else ans[i] = seg[1].ind;
	}
	for( int i=1; i<=n; i++ )
		printf( "%d\n", ans[vid[i]] );
}

int main() {
	input();
	build();
	answer();
}

void pv( vector<int> &v ) {
	for( int t=0; t<(int)v.size(); t++ )
		fprintf( stderr, "%d ", v[t] );
	fprintf( stderr, "\n" );
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值