P8844 [传智杯 #4 初赛] 小卡与落叶

先考虑暴力做法。

对于深度 x\geq x 的点变成黄色,相当于对于每一个深度为 xx 的点,将以它为根的子树中每个点都变成黄色。

但是显然深度为 xx 的结点的数量是 O(n)O(n) 级别的,每次用线段树维护区间覆盖区间求和的理论复杂度上界是 O(mnlogn)O(mn\log n) 的,显然复杂度不对。

但是我们仔细分析可得,操作一里有这么一句话:把整棵树都染绿。

显然每次操作和之前的操作和查询是无关的,对每次查询产生贡献的只有上一次修改操作,并且一次修改至下一次修改之间的所有查询都可以打乱顺序,因为查询不会影响树的数据。

考虑操作离线,对于每个查询操作找到上次的修改,然后将 depdep11 枚举到 nn,对所有深度等于 depdep 的结点线段树维护区间覆盖,覆盖完后查询所有以 depdep 为上一次修改的查询即可。

由于一棵树最多只有 nn 个结点,而区间覆盖最多只会进行 nn 次。由于 n,mn,m 同阶,所以总体复杂度 O(nlogn)O(n \log n)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <utility>
#include <vector>
using namespace std;

const int N = 1e5 + 5;

int n, m;

class SegmentTree
{
public:
	struct Node
	{
		int l, r, sum;
		int tag;
	}tr[N << 2];
	void pushup(int u)
	{
		tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
	}
	void pushdown(int u)
	{
		if (tr[u].tag != -1)
		{
			tr[u << 1].tag = tr[u].tag;
			tr[u << 1].sum = tr[u].tag * (tr[u << 1].r - tr[u << 1].l + 1);
			tr[u << 1 | 1].tag = tr[u].tag;
			tr[u << 1 | 1].sum = tr[u].tag * (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1);
			tr[u].tag = -1;
		}
	}
	void build(int u, int l, int r)
	{
		tr[u] = { l, r, 0, -1 };
		if (l == r) return;
		int mid = l + r >> 1;
		build(u << 1, l, mid);
		build(u << 1 | 1, mid + 1, r);
	}
	void update(int u, int l, int r, int c)
	{
		if (tr[u].l >= l and tr[u].r <= r)
		{
			tr[u].tag = c;
			tr[u].sum = c * (tr[u].r - tr[u].l + 1);
		}
		else
		{
			pushdown(u);
			int mid = tr[u].l + tr[u].r >> 1;
			if (l <= mid) update(u << 1, l, r, c);
			if (r > mid) update(u << 1 | 1, l, r, c);
			pushup(u);
		}
	}
	int query(int u, int l, int r)
	{
		if (tr[u].l >= l and tr[u].r <= r)
		{
			return tr[u].sum;
		}
		pushdown(u);
		int mid = tr[u].l + tr[u].r >> 1, sum = 0;
		if (l <= mid) sum = query(u << 1, l, r);
		if (r > mid) sum += query(u << 1 | 1, l, r);
		return sum;
	}
}f;

vector<int> G[N];
vector<pair<int, int> > p[N];
vector<int> DEP[N];
int sz[N], dep[N], ans[N], idx;
int id[N], idx2;

void dfs(int u, int fa)
{
	dep[u] = dep[fa] + 1;
	DEP[dep[u]].push_back(u);
	sz[u] = 1;
	id[u] = ++idx2;
	for (int i = 0; i < G[u].size(); i++)
	{
		int j = G[u][i];
		if (j != fa)
		{
			dfs(j, u);
			sz[u] += sz[j];
		}
	}
}

int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i < n; i++)
	{
		int u, v;
		scanf("%d%d", &u, &v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	int last = 0;
	for (int i = 1; i <= m; i++)
	{
		int op, x;
		scanf("%d%d", &op, &x);
		if (op == 1)
		{
			last = x;
		}
		else
		{
			p[last].push_back(make_pair(x, ++idx));
		}
	}
	dfs(1, 0);
	f.build(1, 1, n);
	for (int i = 0; i <= n; i++)
	{
		if (p[i].size() == 0) continue;
		if (i == 0)
		{
			for (pair<int, int> j : p[i])
			{
				ans[j.second] = 0;
			}
		}
		else
		{
			f.update(1, 1, n, 0);
			for (int j : DEP[i])
			{
				//printf("%d %d\n", i, j);
				f.update(1, id[j], id[j] + sz[j] - 1, 1);
			}
			for (pair<int, int> j : p[i])
			{
				ans[j.second] = f.query(1, id[j.first], id[j.first] + sz[j.first] - 1);
			}
		}
	}
	for (int i = 1; i <= idx; i++)
	{
		printf("%d\n", ans[i]);
	}
	return 0;
}
posted @   HappyBobb  阅读(6)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示