血压游戏【科大讯飞杯G题】【虚树】

题目链接


  一开始的时候,我往长链剖分上去写,但是写不好,最后写成了当只有一条链的时候是O(N^2)的惨案了。

  然后,开始想别的想法了,于是想(偷窥)到了虚树的做法。

  因为,我们可以发现,一个点,向上影响的时候,只有同等深度的才会同时起作用,只要不是同等深度的时候,那么他们的时间就会是错开的,所以,我们可以对深度来进行处理。

只有发生这种情况的时候,x和y才会同时影响一个结点,不然的话,在相互不影响的直接向上路径上的产生的贡献就是:

dp[u] = max(1, dp[v] - (deep[v] - deep[u]));(dp[v] > 0)

  这里的dp[x]指的是到x结点时候的此时刻的松鼠的数量,因为v在上升的过程中,松鼠要打架,会一只只的挂掉,而且挂掉的数量恰好就是深度差。

  而,有多个点会同时抵达u点的时候,又是怎样的一种情况呢?

  如图,我们假设前面已经计算过了前面所有该时刻到达u点的值,现在算v点,那么就应该是dp[u] += max(1, dp[v] - (deep[v] - deep[u]));(dp[v] > 0)

  那么,我们这样子算出了到达各个点的同一时刻上的松鼠的数量,那么时刻实际上就是与深度有关的,所以,我们用一个vector存储深度,然后每次处理同一深度到达S点时候所能送来的松鼠的数量,就是变相的求出了每个时刻到S点的松鼠数量了。

  于是,我们可以用虚树来解决这个问题了,别忘了最开始的时候就要往栈中push进去S结点,为了方便计算。

  然后,虚树的复杂度为O(N log_{2}(N)),所以总的时间复杂度为O(N log_{2}(N))

  我这里用了欧拉序+RMQ求LCA的方式,因为这样预处理时候是O(N log_{2}(N))的,但是查询时候是O(1)的。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define Big_INF 0x3f3f3f3f3f3f3f3f
#define eps 1e-8
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2e5 + 7;
int N, S, LOG_2[maxN << 1], _UP;
ll a[maxN], ans = 0;
struct Graph
{
    int head[maxN], cnt;
    struct Eddge
    {
        int nex, to;
        Eddge(int a=-1, int b=0):nex(a), to(b) {}
    } edge[maxN << 1];
    inline void addEddge(int u, int v)
    {
        edge[cnt] = Eddge(head[u], v);
        head[u] = cnt++;
    }
    inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
    void clear() { cnt = 0; for(int i=1; i<=N; i++) head[i] = -1; }
} Old, Now;
vector<int> vt[maxN];
struct Grand_Father
{
    int deep[maxN], euler[maxN << 1], Esiz, rid[maxN], dfn[maxN], tot;
    void dfs(int u, int fa)
    {
        deep[u] = deep[fa] + 1; rid[u] = Esiz + 1; dfn[u] = ++tot; _UP = max(_UP, deep[u]); vt[deep[u]].push_back(u);
        for(int i=Old.head[u], v; ~i; i=Old.edge[i].nex)
        {
            v = Old.edge[i].to;
            if(v == fa) continue;
            euler[++Esiz] = u;
            dfs(v, u);
        }
        euler[++Esiz] = u;
    }
    int mn[maxN << 1][20];
    inline void RMQ_Init()
    {
        for(int i=1; i<=Esiz; i++) mn[i][0] = euler[i];
        for(int j=1; (1 << j) <= Esiz; j++)
        {
            for(int i=1; i + (1 << j) - 1 <= Esiz; i++)
            {
                if(deep[mn[i][j - 1]] < deep[mn[i + (1 << (j - 1))][j - 1]]) mn[i][j] = mn[i][j - 1];
                else mn[i][j] = mn[i + (1 << (j - 1))][j - 1];
            }
        }
    }
    inline int Rmq(int l, int r)
    {
        int det = r - l + 1, kk = LOG_2[det];
        if(deep[mn[l][kk]] <= deep[mn[r - (1 << kk) + 1][kk]]) return mn[l][kk];
        else return mn[r - (1 << kk) + 1][kk];
    }
    inline int _LCA(int u, int v)
    {
        int l = rid[u], r = rid[v];
        if(l > r) swap(l, r);
        return Rmq(l, r);
    }
} A_lca;
inline bool cmp(int e1, int e2) { return A_lca.dfn[e1] < A_lca.dfn[e2]; }
int Stap[maxN], Stop;
ll dp[maxN];
inline void Insert(int u)
{
    if(Stop <= 1) { Stap[++Stop] = u; return; }
    int lca = A_lca._LCA(u, Stap[Stop]);
    while(Stop > 1 && A_lca.dfn[lca] <= A_lca.dfn[Stap[Stop - 1]])
    {
        if(dp[Stap[Stop]]) dp[Stap[Stop - 1]] += max(1LL, dp[Stap[Stop]] - (A_lca.deep[Stap[Stop]] - A_lca.deep[Stap[Stop - 1]]));
        dp[Stap[Stop]] = 0;
        Stop--;
    }
    if(lca ^ Stap[Stop])
    {
        if(dp[Stap[Stop]]) dp[lca] += max(1LL, dp[Stap[Stop]] - (A_lca.deep[Stap[Stop]] - A_lca.deep[lca]));
        dp[Stap[Stop]] = 0;
        Stap[Stop] = lca;
    }
    Stap[++Stop] = u;
}
inline void init()
{
    Old.clear(); Now.clear(); A_lca.tot = 0;
    for(int i = 1, j = 2, k = 0; i <= (N << 1); i++)
    {
        if(i == j) { j <<= 1; k++; }
        LOG_2[i] = k;
    }
}
int main()
{
    scanf("%d%d", &N, &S);
    init();
    for(int i=1; i<=N; i++) scanf("%lld", &a[i]);
    for(int i=1, u, v; i<N; i++)
    {
        scanf("%d%d", &u, &v);
        Old._add(u, v);
    }
    A_lca.dfs(S, 0);
    A_lca.RMQ_Init();
    for(int i=_UP, len, id; i>1; i--)
    {
        sort(vt[i].begin(), vt[i].end(), cmp);
        len = (int)vt[i].size();
        Stap[Stop = 1] = S; dp[S] = 0;
        for(int j=0; j<len; j++)
        {
            id = vt[i][j];
            dp[id] = a[id];
            Insert(id);
        }
        while(Stop > 1)
        {
            if(dp[Stap[Stop]]) dp[Stap[Stop - 1]] += max(1LL, dp[Stap[Stop]] - (A_lca.deep[Stap[Stop]] - A_lca.deep[Stap[Stop - 1]]));
            dp[Stap[Stop]] = 0;
            Stop--;
        }
        if(dp[S]) ans += max(1LL, dp[S] - 1);
    }
    if(a[S]) ans += max(1LL, a[S] - 1);
    printf("%lld\n", ans);
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
根据提供的引用内容,EGC代表心电图,脉搏波代表脉搏的波形,心率是指心脏每分钟跳动的次数,心率变异性是指心率在不同时间段内的变化程度,血压是指血液对血管壁的压力。这些指标在医学领域中被广泛用于评估心血管健康和疾病。 以下是关于EGC、脉搏波、心率、心率变异性和血压的介绍: 1. EGC(心电图):心电图是一种记录心脏电活动的方法。它通过将电极放置在身体的特定位置来检测心脏的电信号,并将其转化为图形。心电图可以用于检测心脏疾病、评估心脏功能和监测心脏健康。 2. 脉搏波:脉搏波是指由心脏收缩引起的血液在动脉中传播的波动。脉搏波的形状和特征可以提供关于心脏功能和血管健康的信息。通过分析脉搏波的形态和参数,可以评估心血管系统的状态。 3. 心率:心率是指心脏每分钟跳动的次数。正常成年人的心率通常在60到100次/分钟之间。心率可以通过触摸动脉或使用心率监测设备(如心率表或心率监测器)来测量。 4. 心率变异性:心率变异性是指心率在不同时间段内的变化程度。正常情况下,心率会随着呼吸和其他生理过程的变化而发生变化。心率变异性的分析可以提供关于自主神经系统功能和心血管健康的信息。 5. 血压血压是指血液对血管壁的压力。它由两个值组成:收缩压和舒张压。收缩压是心脏收缩时血液对血管壁的最高压力,舒张压是心脏舒张时血液对血管壁的最低压力。血压的测量通常以毫米汞柱(mmHg)为单位。 综上所述,EGC、脉搏波、心率、心率变异性和血压是用于评估心血管健康和疾病的重要指标。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值