首页 > 其他分享 >P1600 [NOIP2016 提高组] 天天爱跑步

P1600 [NOIP2016 提高组] 天天爱跑步

时间:2022-12-30 23:24:16浏览次数:43  
标签:tmp NOIP2016 head int top son dep 跑步 P1600

//题目大意:有一棵树,在每个节点上会在Pi时刻出现一个观察员,在该时刻观察员如果观察到路过的运动员,那么该观察员的分数加1;
//          现在给定m条路径的起点与终点,每个运动员从0时刻出发,现在询问最终每个观察员的分数
//思路:有画图,看博客
#include<bits/stdc++.h>
using namespace std;
const int M = 3e5 + 11;
int n, m, pat;
int w[M], ans[M], siz[M], dep[M], son[M], f[M], top[M], head[M];
int s[M], t[M], ancestor[M];
int bucket1[M], bucket2[M * 2];
struct OPT {
    int d, tmp;
    OPT() {}
    //OPT(){} means an empty constructor. It does not need any argument, and does nothing.
    OPT(const int& _d, const int& _tmp) :d(_d), tmp(_tmp) {}
    //OPT(){_d, _tmp):d(_d),tmp(_tmp){}. It receives two arguments and it gives the value of _d to the member d, and _tmp to tmp

};
struct edge {
    int to, next;
    edge(int a = 0, int b = 0) {
        to = a, next = b;
    }
}e[M * 2];//存双边
vector <OPT> opt1[M], opt2[M];//上行链、下行链
void add(int u, int v) {
    e[++pat] = { v,head[u] }, head[u] = pat;
    e[++pat] = { u,head[v] }, head[v] = pat;
}
void dfs(int u, int fa) {//我们这里用树链剖分求lca
    f[u] = fa;
    siz[u] = 1, dep[u] = dep[fa] + 1;
    for (int i = head[u]; i != -1; i = e[i].next) {
        if (e[i].to == fa) continue;
        dfs(e[i].to, u);
        siz[u] += siz[e[i].to];
        if (siz[son[u]] < siz[e[i].to]) son[u] = e[i].to;
    }
}//树链剖分求重儿子
void dfs1(int u, int v) {
    top[u] = v;
    if (son[u]) dfs1(son[u], v);
    for (int i = head[u]; i != -1; i = e[i].next) {
        int q = e[i].to;
        if (q == f[u] || q == son[u]) continue;
        dfs1(q, q);
    }
}//剖分
int LCA(int u, int v) {
    while (top[u] != top[v]) {
        dep[top[u]] >= dep[top[v]] ? u = f[top[u]] : v = f[top[v]];
    }
    return dep[u] <= dep[v] ? u : v;
}

void dfs2(int now) {
    int former = bucket1[dep[now] + w[now]];
    for (int i = head[now]; i != -1; i = e[i].next)
        if (e[i].to != f[now])
            dfs2(e[i].to);
    for (int i = 0; i < opt1[now].size(); i++) bucket1[opt1[now][i].d] += opt1[now][i].tmp;
    int latter = bucket1[dep[now] + w[now]];
    ans[now] += latter - former;
}//所以这里是没有算上LCA的贡献的

void dfs3(int now) {
    int former = bucket2[w[now] - dep[now] + M];//////////这里的桶放越界措施+一个M
    for (int i = head[now]; i!=-1; i = e[i].next) if (e[i].to != f[now]) dfs3(e[i].to);
    for (int i = 0; i < opt2[now].size(); i++) bucket2[opt2[now][i].d + M] += opt2[now][i].tmp;
    int latter = bucket2[w[now] - dep[now] + M];
    ans[now] += latter - former;
}
int main() {
    cin >> n >> m;
    memset(head, -1, sizeof(head));
    for (int i = 1, u, v; i < n; ++i)
        cin >> u >> v, add(u, v);
    for (int i = 1; i <= n; i++) cin >> w[i];
    for (int i = 1; i <= m; i++) cin >> s[i] >> t[i];
    dep[0] = 0, dfs(1, 0), dfs1(1, 1);

    for (int i = 1; i <= m; ++i) {
        ancestor[i] = LCA(s[i], t[i]);
        opt1[s[i]].push_back(OPT(dep[s[i]], 1));
        opt1[ancestor[i]].push_back(OPT(dep[s[i]], -1));
    }
    dfs2(1);

    for (int i = 1; i <= m; i++) {
        int dist = dep[s[i]] + dep[t[i]] - 2 * dep[ancestor[i]];
        opt2[t[i]].push_back(OPT((dist - dep[t[i]]), 1));
        if (f[ancestor[i]]) opt2[f[ancestor[i]]].push_back(OPT((dist - dep[t[i]]), -1));
    }
    dfs3(1);

    for (int i = 1; i < n; i++) printf("%d ", ans[i]);
    printf("%d", ans[n]);
    return 0;
}

 

 

 

 

 

 

 

 

标签:tmp,NOIP2016,head,int,top,son,dep,跑步,P1600
From: https://www.cnblogs.com/Aacaod/p/17016028.html

相关文章

  • [NOIP2016 普及组] 回文日期
    [NOIP2016普及组]回文日期题目背景NOIP2016普及组T2题目描述在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。牛牛习惯用\(8\)位数字表示......
  • #yyds干货盘点# 名企真题专题:小招喵跑步
    1.简述:描述小招喵喜欢在数轴上跑来跑去,假设它现在站在点n处,它只会3种走法,分别是:1.数轴上向前走一步,即n=n+1 2.数轴上向后走一步,即n=n-1 3.数轴上使劲跳跃到当前点的两倍,......
  • NOIP2016Day2T2-蚯蚓
    B:蚯蚓时间限制:1Sec  内存限制:512MB题目描述本题中,我们将用符号LcJ表示对c向下取整,例如:L3.0J=L3.1J......
  • NOIP2016Day1T3-换教室
    概率dp经典题。3、换教室时间限制:1Sec内存限制:512MB题目描述在可以选择的课程中,有2n节课程安排在n个时间段上。在第i(1≤i≤n)个时间段上,两节内容相同的课程同时......
  • NOIP2016Day1T2-天天爱跑步
    2、天天爱跑步时间限制:2Sec  内存限制:512MB题目描述小C同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。 《天天爱跑步》是一个养成类游戏,需要玩......
  • 玩具谜题(NOIP2016)
    题目链接:​​玩具谜题​​​提高组日常水题。直接模拟,有需要注意的点会在代码后讲解:#include<bits/stdc++.h>usingnamespacestd;intmain(){intn,m;scanf("%......
  • P2827 NOIP2016 提高组 蚯蚓
    P2827NOIP2016提高组蚯蚓-洛谷|计算机科学教育新生态(luogu.com.cn)事实上,本题疑似所有题解和lyd蓝书上的证明均有误,本篇题解将给出一个严谨的单调性正确性证明......
  • 【luogu P1600】天天爱跑步(线段树合并)(LCA)
    天天爱跑步题目链接:luoguP1600题目大意有一棵树,给你若干条路径,对于每个点,有一个数x,求出有多少条路径的第x个点是当前点。思路考虑把路径拆成两个部分,向上和向下。......
  • 【FAQ】【应用保活问题】跑步类应用切换至后台运行,一段时间后应用进程保活
    【问题描述】跑步类APP为了记录用户的跑步轨迹,怎么才能持续获取手机GPS定位保活?【解决方案】1、目前没有这样的保活白名单;目前只有特殊背景类应用(比如抗疫类软件)可以直接......
  • [NOI Online #1 入门组] 跑步 题解
    [NOIOnline#1入门组]跑步题解一个经典问题:计数将正整数\(n\)拆分为若干个正整数的方案数,这里拆成的正整数是无序的,对\(P\)取模。容易得到\(O(n^2)\)解法设\(f_{i,j......