雅礼培训4.3 Problem A 【点分治】

题目简述

一个\(N\)个节点的树,有\(M\)个炸弹分布在一些节点上,有各自的威力,随着其他点距离增大对其他点的伤害呈等差减小,直至为0

问每个点受到的伤害

题解

QAQ考场代码没处理好有些炸弹威力很大这个事实,,数组爆掉。。。

AC算法直接变暴力分,,,

点分治即可

我是每次将子树内所有的炸弹统计到根来,再用一个差分数组求出各个深度受到的伤害,累加入每个节点的答案

但是由于可能会出现伤害来自同一个子树的情况,我们再对每个子树做一遍撤销

常数略大,,经玄学优化强行卡入时限

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
using namespace std;
const int maxn = 500005,maxm = 600005,INF = 100000000;
inline int read(){
    int out = 0; char c = getchar();
    while (c < 48 || c > 57) c = getchar();
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out;
}
inline void write(LL x){
    LL tmp = 0; int cnt = 0;
    while (x) tmp = (tmp << 3) + (tmp << 1) + x % 10,x /= 10,cnt++;
    while (cnt--) putchar(tmp % 10 + 48),tmp /= 10;
    putchar(‘\n‘);
}
int h[maxn],ne = 2,n,m;
struct EDGE{int to,nxt;}ed[maxn * 2];
int F[maxn],Siz[maxn],rt,sum,vis[maxn];
int siz[maxn],st[maxm],top,d[maxn],fa[maxn],nd[maxn],ndi;
int md;
LL ans[maxn],D[maxn];
vector<int> power[maxn];
inline void build(int u,int v){
    ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;
    ed[ne] = (EDGE){u,h[v]}; h[v] = ne++;
}
void getRT(int u){
    Siz[u] = 1 + power[u].size();
    F[u] = 0;
    Redge(u) if (!vis[to = ed[k].to] && to != fa[u]){
        fa[to] = u;
        getRT(to);
        Siz[u] += Siz[to];
        F[u] = max(F[u],Siz[to]);
    }
    F[u] = max(F[u],sum - Siz[u]);
    if (F[u] < F[rt]) rt = u;
}
void dfs1(int u){
    Siz[u] = 1 + power[u].size(); siz[u] = 1;
    nd[++ndi] = u;
    md = max(md,d[u]);
    Redge(u) if (!vis[to = ed[k].to] && to != fa[u]){
        fa[to] = u; d[to] = d[u] + 1;
        dfs1(to);
        Siz[u] += Siz[to];
        siz[u] += siz[to];
    }
}
void dfs4(int u){
    nd[++ndi] = u;
    for (int j = 0; j < power[u].size(); j++){
        if (power[u][j] > d[u] + 1) st[++top] = power[u][j] - d[u] - 1;
    }
    Redge(u) if (!vis[to = ed[k].to] && to != fa[u]){
        dfs4(to);
    }
}
void dfs5(int u){
    ans[u] -= D[d[u]];
    Redge(u) if (!vis[to = ed[k].to] && to != fa[u]){
        dfs5(to);
    }
}
void cal(int u){
    top = 0;
    for (int j = 0; j < power[u].size(); j++)
        if (power[u][j] > 2) st[++top] = power[u][j] - 2;
    for (int i = 0; i <= siz[u]; i++) D[i] = 0;
    ndi = 0;
    Redge(u) if (!vis[to = ed[k].to] && to != fa[u]){
        dfs4(to);
    }
    for (int i = 1; i <= top; i++){
        if (st[i] <= md){
            D[1] += st[i];
            D[2] += -1 - st[i];
            D[st[i] + 2] += 1;
        }
        else {
            D[1] += st[i];
            D[2] += -1 - st[i];
        }
    }
    for (int i = 1; i <= siz[u]; i++) D[i] += D[i - 1];
    for (int i = 1; i <= siz[u]; i++) D[i] += D[i - 1];
    ans[u] -= D[1];
    for (int i = 1; i <= ndi; i++) ans[nd[i]] -= D[d[nd[i]]];
}
void solve(int u){
    vis[u] = true; siz[u] = 1; Siz[u] = 1 + power[u].size();
    ndi = 0; md = 0;
    Redge(u) if (!vis[to = ed[k].to]){
        fa[to] = u; d[to] = 1;
        dfs1(to);
        siz[u] += siz[to];
        Siz[u] += Siz[to];
    }
    md += 2;
    if (Siz[u] == siz[u]) return;
    top = 0;
    for (int j = 0; j < power[u].size(); j++) st[++top] = power[u][j];
    for (int i = 1; i <= ndi; i++){
        int v = nd[i];
        for (int j = 0; j < power[v].size(); j++){
            if (power[v][j] > d[v]) st[++top] = power[v][j] - d[v];
        }
    }
    for (int i = 0; i <= siz[u]; i++) D[i] = 0;
    for (int i = 1; i <= top; i++){
        if (st[i] <= md){
            D[0] += st[i];
            D[1] += -1 - st[i];
            D[st[i] + 1] += 1;
        }
        else {
            D[0] += st[i];
            D[1] += -1 - st[i];
        }
    }
    for (int i = 1; i <= siz[u]; i++) D[i] += D[i - 1];
    for (int i = 1; i <= siz[u]; i++) D[i] += D[i - 1];
    ans[u] += D[0];
    for (int i = 1; i <= ndi; i++) ans[nd[i]] += D[d[nd[i]]];
    Redge(u) if (!vis[to = ed[k].to]){
        if (siz[to] == Siz[to]) continue;
        cal(to);
    }
    Redge(u) if (!vis[to = ed[k].to]){
        if (siz[to] == Siz[to]) continue;
        sum = Siz[to]; F[rt = 0] = INF;
        getRT(to);
        solve(rt);
    }
}
int main(){
    //double t = clock();
    //freopen("1.in","r",stdin);
    //freopen("a.out","w",stdout);
    n = read(); m = read();
    int pos,w;
    for (int i = 2; i <= n; i++) build(i,read());
    for (int i = 1; i <= m; i++){
        pos = read(); w = read();
        power[pos].push_back(w);
    }
    F[rt = 0] = INF; sum = n + m;
    getRT(1);
    solve(rt);
    for (int i = 1; i <= n; i++) write(ans[i]);
    //cerr << (clock() - t) / CLOCKS_PER_SEC << ‘s‘ << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/8711249.html

时间: 2024-10-07 05:29:50

雅礼培训4.3 Problem A 【点分治】的相关文章

雅礼培训day1 世界线 Worldline

题目大意: 给出一个有向无环图,要求对于图中的u,v,t三点,满足u->v,v->t,u->t,经过观察我们发现就是要将图中每一个点连接所有他可以达到的点,最后输出连接的边的数量. 对此我们可以dfs求出每一个点可以到达其他的点边,最后用求出的边数减去原来已经连接的边,其中用bitset优化. 代码送上: 1 #include <cstdio> 2 #include <bitset> 3 #include <iostream> 4 #define Fo

雅礼培训day2 时间机器 machine

题目大意: 给你两组区间,求覆盖问题. 对于这个问题我们可以针对每个区间的左端点进行排序,在枚举节点时,在左端点满足要求的情况下,是使右端点尽量靠近节点的右端点,使用map来优化 代码送上: 1 #include <cstdio> 2 #include <algorithm> 3 #include <map> 4 5 #define For(i, j, k) for(int i = j; i <= k; i++) 6 #define y second 7 8 9

雅礼培训 1.2

模拟赛 串(string) [题目描述]给定一个由小写字母组成的字符串 s,每次你可以删去它的一个非回文子串,求删成空串的最小次数.[输入数据]第一行一个整数 t 表示数据组数.每组数据第一行一个整数 n 表示字符串长度,第二行一个字符串 s.[输出数据]每组数据输出一行一个整数表示答案,如果无法删成空串输出-1.[样例输入]27abcdcba3xxx[样例输出]2-1[样例解释]对于第一个样例,一种最优方案为 abcdcba->adcba->空串.[数据范围]对于 30%的数据,n<=

#6030. 【雅礼集训 2017 Day1】矩阵

#6030. 「雅礼集训 2017 Day1」矩阵 题目描述 有一个 n×n  的矩阵,每个位置 (i,j) 如果是 . 表示为白色,如果是 # 表示为黑色. 初始时,每个位置可以是黑色或白色的,(i,j)  位置的值会作为 ai,j 给你. 现在有一种操作,选择两个整数 i,j∈[1,n],记 (i,1),(i,2),…,(i,n) (i, 1), (i, 2)的颜色为 C1,C2,…Cn ??,将 (1,j),(2,j),…,(n,j)  的颜色赋为 C1,C2,…,Cn ??. 你的任务是

2017雅礼省选集训做题记录

嘛,最近在补雅礼省选前集训的题.都是我会做的题..那一定是最水的那些题啦 题目在loj.ac上都有.过段时间如果搬了雅礼NOI集训的题应该也会做做的吧.. Day1 T1 一道经典套路题,做法跟UOJ #228基础数据结构练习题类似. 使用线段树维护.考虑相邻两个数的差值最多变化log次.也就是说,对于每个区间,只要操作二进行大概log次就能使得这个区间内所有数完全一样.所以对于操作二,只要记录一下区间最大最小值,就能直接打标记或者暴力DFS下去. 和UOJ那个题一样,注意一个特殊情况,就是一个

雅礼学习10.2

雅礼学习10.2 上午考试解题报告 各题状况(爆零) T1 想了10多分钟,暴力只有一个极大复杂度的想法,显然不可过,但还是写了,然后就全TLE也是...意料之中 T2 暴力很好写,但是错误理解了Tim给的部分分的意思:先给了一个\(a_i\le 10^9\),然后部分分里面没有提到\(a_i\)的情况,我就忽略了\(a_i\)的大小对答案统计的影响... 换句话说,我当时要是写了离散化,就是\(43\)分到手. T3 题目要求的输出可以分成三个问题,第一个问题正确 的话可以得到这个点的\(25

雅礼学习10.4

雅礼学习10.4 上午考试 各题状况 T1 莫名其妙20分了. 考场上一眼秒掉了这个题目:这不就是个并查集捆绑+快速幂么 然后开开心心这个点如果有这个质因子的话\(fa\)就指向这个质因子,而每个数字有多个质因子... 多个质因子在相互指\(fa\)的时候指乱套了.... 对拍的时候看出来的,然后用\(1\)个多小时来调这份代码,最后自己都不知道这东西在干嘛了,就凉了. T2 写了个暴力枚举,期望\(20\)实际\(20\) T3 看到成绩之后:这题怎么会爆\(long long\)的??? 然

雅礼学习10.5

雅礼学习10.5 上午考试 各题状况 T1 模拟挂成\(10\)分?? 每次更新答案的时候位置搞错了. 想到了可能是线段树动态开点,但没写出来,因为标记下传不会... T2 理解错了题目含义. 选出的\(m\)个物品中,至少要有\(k\)个是\(A\)喜欢的,至少\(k\)个是\(B\)喜欢的 那么很显然只要满足了上面的限制条件,俩人都不喜欢的也能选... 但考场上没想到这层 就凉了 正解变骗分,\(15\)分 T3 搞完上面两个题目之后没剩多少时间,就随便扔了个东西上去.. 也不知道写的是个啥

雅礼学习10.7

雅礼学习10.7 上午考试 各题状况 全TM神仙题... \(T1\) \(35\)分暴力 \(T2\) 我\(n=1\)的时候直接输出了\(1\),连这个格子上是否有方块都没判,当时是感觉...难道这个部分分也会卡么 结果出题人就这么卡了..就一分都没有了 太毒瘤了. \(T3\) 成功骗\(8\)分 做了一段时间之后去做牛客网的来着. 跟人要了份暴力 然后我TM..从紫名变成灰名了???? 题目及考场代码 T1 /* * 暴力思路:从初始位置开始进行bfs */ #include<queue