QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#745290 | #9373. Query on Tree | JZYZ# | WA | 0ms | 16076kb | C++14 | 5.7kb | 2024-11-14 08:58:26 | 2024-11-14 08:58:26 |
Judging History
answer
// 终于懂了。。。
// 首先就是把所有距离x不超过k的点都加上 v 有两种做法:
// 第一种做法可以参考JOIsc 洒水器一题,可以只做一遍。第二种做法就是把不超过k, 变成k次恰好为 i,需要做k遍,但是可以过
// 我们采用第二种做法
// 首先考虑只有 1, 2 操作该怎么办
// 发现可以求出一个 bfs 序列, 那么同层的点会形成一段区间,然后就是可以暴力从u往父亲跳k次,那么每次修改就是一段区间,复杂度为qklog
// 如果加上3操作呢? 发现这时候一棵子树对应的明显不是一段区间。考虑把这两种序列结合起来
// 我们按照dfs序,依次把每个点对应的k级儿子序列加入,那么序列总长度为n,每个点只有一个k级祖先。
// 然后每个点的子树里到它的距离为d(d <= k) 的点都对应了一段区间
// 考虑把这样的区间都记录下来, 然后每次修改就好了
#include<bits/stdc++.h>
#define pb emplace_back
#define MP make_pair
using namespace std;
const int N = 2e5 + 10;
typedef long long LL;
typedef pair< int, int > PII;
int n, q, z;
int L[N][10], R[N][10];
int lt[N], rt[N];
int dfn[N], ID[N], dfc, fat[N];
LL a[N];
vector< int > E[N];
struct SegmentTree {
int l, r; LL tag, mx;
#define l(x) t[x].l
#define r(x) t[x].r
#define tag(x) t[x].tag
#define mx(x) t[x].mx
}t[N * 4];
void dfs0(int x, int fa) {
fat[x] = fa;
for(auto v : E[x]) if(v != fa) dfs0(v, x);
}
void bfs(int rt) { // 按照 bfs 序插入
queue< PII > q;
q.push(MP(rt, 0));
for(int i = 0; i <= 9; i ++ ) L[rt][i] = 1e9, R[rt][i] = -1e9;
while(!q.empty()) {
PII u = q.front(); q.pop();
int x = u.first, dep = u.second;
if(!dfn[x]) dfn[x] = ++ dfc, ID[dfc] = x;
L[rt][dep] = min(L[rt][dep], dfn[x]);
R[rt][dep] = max(R[rt][dep], dfn[x]);
if(dep < 9) {
for(auto v : E[x]) if(v != fat[x]) q.push(MP(v, dep + 1));
}
}
}
void dfs1(int x, int fa) {
bfs(x); lt[x] = L[x][9], rt[x] = R[x][9];
for(auto v : E[x]) {
if(v != fa) {
dfs1(v, x);
lt[x] = min(lt[x], lt[v]);
rt[x] = max(rt[x], rt[v]);
}
}
}
void spread(int p) {
if(tag(p)) {
mx(p << 1) += tag(p); mx(p << 1 | 1) += tag(p);
tag(p << 1) += tag(p); tag(p << 1 | 1) += tag(p);
tag(p) = 0;
}
}
void update(int p) {
mx(p) = max(mx(p << 1), mx(p << 1 | 1));
}
void change(int p, int l, int r, LL v) {
if(l > r) return ;
if(l <= l(p) && r >= r(p)) {
tag(p) += v;
mx(p) += v;
return ;
}
spread(p);
int mid = (l(p) + r(p) >> 1);
if(l <= mid) change(p << 1, l, r, v);
if(r > mid) change(p << 1 | 1, l, r, v);
update(p);
}
void build(int p, int l, int r) {
l(p) = l, r(p) = r;
if(l == r) {
// cout << "kkk" << p << ' ' << ID[l] << ' ' << a[ID[l]] << endl;
mx(p) = a[ID[l]];
return ;
}
int mid = (l + r >> 1);
build(p << 1, l, mid); build(p << 1 | 1, mid + 1, r);
update(p);
}
LL ask(int p, int l, int r) {
if(l > r) return -1e18;
if(l <= l(p) && r >= r(p)) return mx(p);
spread(p);
int mid = (l(p) + r(p) >> 1);
if(r <= mid) return ask(p << 1, l, r);
else if(l > mid) return ask(p << 1 | 1, l, r);
else return max(ask(p << 1, l, r), ask(p << 1 | 1, l, r));
}
LL modify(int x, int k, LL v) { // 把所有与x距离为k的点加上v, 并且求出最大值
int now = x, d = k; int lst = -1; LL res = -1e18;
while(now != 0) {
if(now == x || d == 0) {
// cout << "UUU" << ' ' << now <<' ' << R[now][d] << ' ' << L[now][d] << ' ' << ask(1, L[now][d], R[now][d])<< endl;
if(R[now][d] >= L[now][d]) {
change(1, L[now][d], R[now][d], v);
res = max(res, ask(1, L[now][d], R[now][d]));
}
}
else {
if(R[now][d] >= L[now][d]) {
change(1, L[now][d], min(R[now][d], L[lst][d - 1] - 1), v);
res = max(res, ask(1, L[now][d], min(R[now][d], L[lst][d - 1] - 1)));
if(R[lst][d - 1] > 0) {
change(1, max(L[now][d], R[lst][d - 1] + 1), R[now][d], v);
res = max(res, ask(1, max(L[now][d], R[lst][d - 1] + 1), R[now][d]));
}
}
}
lst = now, d --; now = fat[now];
if(d == -1) break;
}
return res;
}
LL Tc(int x, LL v) { // 把 x 的子树加 v
LL res = -1e18;
if(rt[x] >= lt[x]) {
change(1, lt[x], rt[x], v);
res = max(res, ask(1, lt[x], rt[x]));
}
for(int i = 0; i <= 8; i ++ ) {
if(L[x][i] <= R[x][i]) {
change(1, L[x][i], R[x][i], v);
res = max(res, ask(1, L[x][i], R[x][i]));
}
}
return res;
}
int main() {
// freopen("ex_neighbor2.in", "r", stdin);
// freopen("data.out", "w", stdout);
scanf("%d%d%d", &n, &q, &z);
for(int i = 1; i <= n; i ++ ) scanf("%lld", &a[i]);
for(int i = 1; i < n; i ++ ) {
int u, v; scanf("%d%d", &u, &v);
E[u].pb(v); E[v].pb(u);
}
dfs0(1, 0);
dfs1(1, 0); // 按照dfs序插入这个点的9级儿子
// cout <<"TTT" <<dfc << endl;
// for(int i = 1; i <= n; i ++ ) {
// printf("lt[%d] = %d\n rt[%d] = %d\n", i, lt[i], i, rt[i]);
// }
// for(int i = 1; i <= n; i ++ ) {
// for(int j = 0; j <= 9; j ++ ) {
// if(L[i][j] > n) R[i][j] = n + 1;
// printf("L[%d][%d] = %d R[%d][%d] = %d\n", i, j, L[i][j], i, j, R[i][j]);
// }
// }
build(1, 1, n);
while(q -- ) {
int opt, x, k;
LL v, res = -1e18;
scanf("%d", &opt);
if(opt == 1) {
scanf("%d%d%lld", &x, &k, &v);
res = modify(x, k, v);
}
else if(opt == 2) {
scanf("%d%d%lld", &x, &k, &v);
res = -1e18;
for(int i = 0; i <= k; i ++ ) {
LL vv = modify(x, i, v);
res = max(res, vv);
// cout << "HHH" <<i << ' ' << vv << endl;
}
}
else {
scanf("%d%lld", &x, &v);
res = Tc(x, v);
}
if(res < -3e14) puts("GG");
else printf("%lld\n", res);
}
return 0;
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 0
Wrong Answer
time: 0ms
memory: 16076kb
input:
1 5 5 1 2 1 3 2 1 2 2 3 2 4 4 5 2 2 1 0 1 2 1 3 3 4 -5 2 5 2 3 3 2 -1
output:
3 5 30 30 33
result:
wrong answer 2nd lines differ - expected: '6', found: '5'