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 n−1个数描述 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=i∗yi,请输出 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 1∗1+2∗0+3∗3+4∗0+5∗3+6∗0+7∗1=32.
数据范围:
对于100%的数据 T ≤ 6 , n , m , c ≤ 1 0 5 T\leq 6,n,m,c\leq 10^5 T≤6,n,m,c≤105,
1 ≤ a ≤ n , 0 ≤ l ≤ n , 0 ≤ c ≤ c 1\leq a\leq n,0\leq l\leq n,0\leq c\leq c 1≤a≤n,0≤l≤n,0≤c≤c
解题分析
这道题真的妙啊QAQ… 一开始想的是点分治, 发现似乎每层分治中心无法维护信息…
那么反过来我们看这道题的要求: 子树覆盖。 如果没有深度限制的话, 我们直接转为 D F S DFS DFS序上的序列操作就可以了。
现在有了深度, 相当于多了一维, 所以我们第一维为 D F S DFS DFS序, 第二维为深度, 将树上的点转化为平面上的点, 修改操作就变成了矩形内的赋值操作, 查询变为单点查询, 我们用 K D − T r e e KD-Tree KD−Tree维护就好了。
不涉及修改、插入操作, 连重构都不用写…
代码如下:
#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);
}
}