[BZOJ 4154] [Ipsc2015] Generating Synergy

8 篇文章 0 订阅
5 篇文章 0 订阅
BZOJ传送门

题目描述

给定一棵以 1 1 1为根的有根树,初始所有节点颜色为 1 1 1,每次将距离节点 a a a不超过 l l l a a a的子节点染成 c c c(包括 a a a节点),或询问点 a a a的颜色 。

输入输出格式

输入格式

第一行一个数 T T T,表示数据组数

接下来每组数据的第一行三个数 n , c , q n,c,q n,c,q表示结点个数,颜色数和操作数

接下来一行 n − 1 n-1 n1个数描述 2... n 2...n 2...n的父节点

接下来 q q q行每行三个数 a , l , c a,l,c a,l,c

c c c 0 0 0,表示询问 a a a的颜色

否则将距离 a a a不超过 l l l a a a的子节点染成 c c c

输出格式

设当前是第 i i i个操作, y i y_i yi为本次询问的答案(若本次操作是一个修改则 y i y_i yi 0 0 0),令 z i = i ∗ y i z_i=i*y_i zi=iyi,请输出 z 1 + z 2 + . . . + z q z_1+z_2+...+z_q z1+z2+...+zq 1 0 9 + 7 10^9+7 109+7

输入输出样例

输入样例#1
1
4 3 7
1 2 2
3 0 0
2 1 3
3 0 0
1 0 2
2 0 0
4 1 
4 0 0
输出样例#1
32

说明

1 , 3 , 5 , 7 1,3,5,7 1,3,5,7的询问的答案分别为 1 , 3 , 3 , 1 1,3,3,1 1,3,3,1,所以答案为 1 ∗ 1 + 2 ∗ 0 + 3 ∗ 3 + 4 ∗ 0 + 5 ∗ 3 + 6 ∗ 0 + 7 ∗ 1 = 32 1*1+2*0+3*3+4*0+5*3+6*0+7*1=32 11+20+33+40+53+60+71=32.

数据范围:

对于100%的数据 T ≤ 6 , n , m , c ≤ 1 0 5 T\leq 6,n,m,c\leq 10^5 T6,n,m,c105,

1 ≤ a ≤ n , 0 ≤ l ≤ n , 0 ≤ c ≤ c 1\leq a\leq n,0\leq l\leq n,0\leq c\leq c 1an,0ln,0cc

解题分析

这道题真的妙啊QAQ… 一开始想的是点分治, 发现似乎每层分治中心无法维护信息…

那么反过来我们看这道题的要求: 子树覆盖。 如果没有深度限制的话, 我们直接转为 D F S DFS DFS序上的序列操作就可以了。

现在有了深度, 相当于多了一维, 所以我们第一维为 D F S DFS DFS序, 第二维为深度, 将树上的点转化为平面上的点, 修改操作就变成了矩形内的赋值操作, 查询变为单点查询, 我们用 K D − T r e e KD-Tree KDTree维护就好了。

不涉及修改、插入操作, 连重构都不用写…

代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <cmath>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 100050
#define ll long long
#define MOD 1000000007ll
bool neg;
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc)
	if(c == '-') neg = true;
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
	if(neg) neg = false, x = -x;
}
struct Node {int cood[2], lim[2][2], son[2], tag, col;} tree[MX], tar;
struct Edge {int to, nex;} edge[MX << 1];
int lb[MX], rb[MX], dep[MX], head[MX];
int dot, q, arr, cnt, dim, climit, mnx, mxx, mny, mxy, root;
IN void add(R int from, R int to)
{edge[++cnt] = {to, head[from]}, head[from] = cnt;}
IN bool operator < (const Node &x, const Node &y)
{return x.cood[dim] == y.cood[dim] ? x.cood[dim ^ 1] < y.cood[dim ^ 1] : x.cood[dim] < y.cood[dim];}
IN bool operator == (const Node &x, const Node &y)
{return x.cood[0] == y.cood[0] && x.cood[1] == y.cood[1];}
void DFS(R int now, R int fa)
{
	lb[now] = ++arr;
	for (R int i = head[now]; i; i = edge[i].nex)
	{
		if(edge[i].to == fa) continue;
		dep[edge[i].to] = dep[now] + 1;
		DFS(edge[i].to, now);
	}
	rb[now] = arr;
}
void reset()
{std::memset(head, cnt = arr = 0, sizeof(head));}
namespace KDT
{
	#define ls tree[now].son[0]
	#define rs tree[now].son[1]
	IN void pushup(R int now)
	{
		tree[now].lim[0][0] = tree[now].lim[0][1] = tree[now].cood[0];
		tree[now].lim[1][0] = tree[now].lim[1][1] = tree[now].cood[1];
		if(ls)
		{
			tree[now].lim[0][0] = std::min(tree[now].lim[0][0], tree[ls].lim[0][0]);
			tree[now].lim[0][1] = std::max(tree[now].lim[0][1], tree[ls].lim[0][1]);
			tree[now].lim[1][0] = std::min(tree[now].lim[1][0], tree[ls].lim[1][0]);
			tree[now].lim[1][1] = std::max(tree[now].lim[1][1], tree[ls].lim[1][1]);
		}
		if(rs)
		{
			tree[now].lim[0][0] = std::min(tree[now].lim[0][0], tree[rs].lim[0][0]);
			tree[now].lim[0][1] = std::max(tree[now].lim[0][1], tree[rs].lim[0][1]);
			tree[now].lim[1][0] = std::min(tree[now].lim[1][0], tree[rs].lim[1][0]);
			tree[now].lim[1][1] = std::max(tree[now].lim[1][1], tree[rs].lim[1][1]);
		}
	}
	IN void pushdown(R int now)
	{
		if(tree[now].tag)
		{
			if(ls) tree[ls].tag = tree[ls].col = tree[now].tag;
			if(rs) tree[rs].tag = tree[rs].col = tree[now].tag;
			tree[now].tag = 0;
		}
	}
	int build(R int lef, R int rig, R int dm)
	{
		int now = lef + rig >> 1; dim = dm;
		std::nth_element(tree + lef, tree + now, tree + rig + 1);
		if(now > lef) ls = build(lef, now - 1, dm ^ 1);
		if(now < rig) rs = build(now + 1, rig, dm ^ 1);
		pushup(now); return now;
	}
	IN bool init(R int dx, R int ux, R int dy, R int uy)//当前管理区间完全在修改区间内
	{return dx >= mnx && ux <= mxx && dy >= mny && uy <= mxy;}
	IN bool outit(R int dx, R int ux, R int dy, R int uy)//完全在修改区间外
	{return dx > mxx || ux < mnx || dy > mxy || uy < mny;}
	void modify(R int now, R int del)
	{
		if(!now) return;
		if(init(tree[now].lim[0][0], tree[now].lim[0][1], tree[now].lim[1][0], tree[now].lim[1][1])) return tree[now].tag = tree[now].col = del, void();
		if(outit(tree[now].lim[0][0], tree[now].lim[0][1], tree[now].lim[1][0], tree[now].lim[1][1])) return;
		pushdown(now);
		if(init(tree[now].cood[0], tree[now].cood[0], tree[now].cood[1], tree[now].cood[1])) tree[now].col = del;
		modify(ls, del), modify(rs, del);
	}
	int query(R int now, R int dm)
	{
		dim = dm; pushdown(now);
		if(tree[now] == tar) return tree[now].col;
		if(tree[now] < tar) return query(rs, dm ^ 1);
		else return query(ls, dm ^ 1);
	}
	#undef ls
	#undef rs
}
int main(void)
{
	int a, b, c, T;
	in(T);
	W (T--)
	{
		reset();
		in(dot), in(climit), in(q);
		for (R int i = 2; i <= dot; ++i)
		in(a), add(a, i), add(i, a);
		dep[1] = 1; DFS(1, 0);
		for (R int i = 1; i <= dot; ++i)
		tree[i].cood[0] = lb[i], tree[i].cood[1] = dep[i], tree[i].col = 1, tree[i].tag = tree[i].son[0] = tree[i].son[1] = 0;
		root = KDT::build(1, dot, 0);
		ll ans = 0;
		for (R int i = 1; i <= q; ++i)
		{
			in(a), in(b), in(c);
			if(!c)
			{
				tar.cood[0] = lb[a], tar.cood[1] = dep[a];
				(ans += 1ll * KDT::query(root, 0) * i) %= MOD;
			}
			else
			{
				mnx = lb[a], mxx = rb[a], mny = dep[a], mxy = dep[a] + b;
				KDT::modify(root, c);
			}
		}
		printf("%lld\n", ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值