zoukankan      html  css  js  c++  java
  • 洛谷 P3722 [AH2017/HNOI2017]影魔

    奈文摩尔有 (n) 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 (1)(n)。第 (i) 个灵魂的战斗力为 (k_i),灵魂们以点对的形式为影魔提供攻击力。对于灵魂对 (i, j (ilt j)) 来说,若不存在 (k_s (ilt slt j)) 大于 (k_i) 或者 (k_j),则会为影魔提供 (p_1) 的攻击力。另一种情况,令 (c)(k_{i + 1}, k_{i + 2}, cdots, k_{j -1}) 的最大值,若 (c) 满足:(k_i lt c lt k_j),或者 (k_j lt c lt k_i),则会为影魔提供 (p_2) 的攻击力,当这样的 (c) 不存在时,自然不会提供这 (p_2) 的攻击力;其他情况的点对,均不会为影魔提供攻击力。

    影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任意一段区间 ([a, b]),位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑所有满足 (ale ilt jle b) 的灵魂对 (i, j) 提供的攻击力之和。

    顺带一提,灵魂的战斗力组成一个 (1)(n) 的排列:(k_1, k_1, cdots, k_n)

    简明题意:有一个n的排列k,对于一个区间([l,r]),如果(k_l)(k_r)分别是这个区间的最大值和次大值,那么产生(p_1)的贡献,如果(s=max_{i=l+1}^{r-1} k_i)满足(k_l<s<k_r),则会产生(p_2)的贡献,每次询问一个区间的答案,答案为这个区间所有子区间产生的贡献

    乍一看不太能做的样子,所以我们考虑离线操作

    先对每个i处理出向左第一个比i大的数的下标(L_i),向右第一个比i大的数的下标(R_i),这个可以直接用单调栈求出

    然后考虑产生的贡献

    1. 区间([L_i,R_i])会产生(p_1)的贡献
    2. 所有左端点在([L_i+1,i-1]),右端点是(R_i)的区间会产生(p_2)的贡献
    3. 所有左端点是(L_i),右端点在([i+1,R_i-1])的区间会产生(p_2)的贡献

    于是我们离线之后每次扫到(R_i)时就做一次贡献,把询问拆成r询问一次答案减去l-1询问一次的答案,然后就做完了

    不要忘了所有的([i,i+1])也会产生(p_1)的贡献

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #define zrt k << 1
    #define yrt k << 1 | 1
    const int N = 2e5;
    using namespace std;
    struct Q
    {
        int x,id,typ,l,r;
    }q[N * 2 + 5];
    int n,p1,p2,m,k[N + 5],L[N + 5],R[N + 5],stk[N + 5],top,Q_cnt,m_cnt;
    long long ans[N + 5];
    int cmp(Q x,Q y)
    {
        return x.x < y.x;
    }
    struct Seg
    {
        long long sm[N * 4 + 5],tag[N * 4 + 5];
        void jia(int k,int l,int r,long long z)
        {
            tag[k] += z;
            sm[k] += z * (r - l + 1);
        }
        void pushdown(int k,int l,int r,int mid)
        {
            if (tag[k])
            {
                jia(zrt,l,mid,tag[k]);
                jia(yrt,mid + 1,r,tag[k]);
                tag[k] = 0;
            }
        }
        void pushup(int k)
        {
            sm[k] = sm[zrt] + sm[yrt];
        }
        void add(int k,int l,int r,int x,int y,int z)
        {
            if (x > y)
                return;
            if (l >= x && r <= y)
            {
                tag[k] += z;
                sm[k] += 1ll * z * (r - l + 1);
                return;
            }
            int mid = l + r >> 1;
            pushdown(k,l,r,mid);
            if (x <= mid)
                add(zrt,l,mid,x,y,z);
            if (y > mid)
                add(yrt,mid + 1,r,x,y,z);
            pushup(k);
        }
        long long query(int k,int l,int r,int x,int y)
        {
            if (x > y)
                return 0;
            if (l >= x && r <= y)
                return sm[k];
            int mid = l + r >> 1;
            pushdown(k,l,r,mid);
            if (x > mid)
                return query(yrt,mid + 1,r,x,y);
            else
                if (y <= mid)
                    return query(zrt,l,mid,x,y);
                else
                    return query(zrt,l,mid,x,y) + query(yrt,mid + 1,r,x,y);
        }
    }tree;
    struct modi
    {
        int l,r,x,v;
    }t[N * 3 + 5];
    int com(modi x,modi y)
    {
        return x.x < y.x;
    }
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&p1,&p2);
        for (int i = 1;i <= n;i++)
            scanf("%d",&k[i]);
        int l,r;
        for (int i = 1;i <= m;i++)
        {
            scanf("%d%d",&l,&r);
            q[++Q_cnt].x = l - 1;
            q[Q_cnt].id = i;
            q[Q_cnt].typ = -1;
            q[Q_cnt].l = l;
            q[Q_cnt].r = r;
            q[++Q_cnt].x = r;
            q[Q_cnt].id = i;
            q[Q_cnt].typ = 1;
            q[Q_cnt].l = l;
            q[Q_cnt].r = r;
            ans[i] = (r - l) * p1;
        }
        k[n + 1] = n + 1;
        for (int i = 1;i <= n + 1;i++)
        {
            while (top && k[stk[top]] < k[i])
                R[stk[top--]] = i;
            stk[++top] = i;
        }
        top = 0;
        for (int i = n;i >= 1;i--)
        {
            while (top && k[stk[top]] < k[i])
                L[stk[top--]] = i;
            stk[++top] = i;
        }
        for (int i = 1;i <= n;i++)
        {
            if (L[i] && R[i] <= n)
                t[++m_cnt] = (modi){L[i],L[i],R[i],p1};
            if (L[i] + 1 <= i - 1 && R[i] <= n)
                t[++m_cnt] = (modi){L[i] + 1,i - 1,R[i],p2};
            if (i + 1 <= R[i] - 1 && L[i])
                t[++m_cnt] = (modi){i + 1,R[i] - 1,L[i],p2};
        }
        sort(q + 1,q + Q_cnt + 1,cmp);
        sort(t + 1,t + m_cnt + 1,com);
        int j = 1,k = 1;
        while (!q[k].x)
            k++;
        for (int i = 1;i <= n;i++)
        {
            while (t[j].x <= i && j <= m_cnt)
            {
                tree.add(1,1,n,t[j].l,t[j].r,t[j].v);
                j++;
            }
            while (q[k].x <= i && k <= Q_cnt)
            {
                ans[q[k].id] += q[k].typ * tree.query(1,1,n,q[k].l,q[k].r);
                k++;
            }
        }
        for (int i = 1;i <= m;i++)
            printf("%lld
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    分层图最短路(DP思想) BZOJ2662 [BeiJing wc2012]冻结
    动态规划 BZOJ1925 地精部落
    线性DP SPOJ Mobile Service
    线性DP codevs2185 最长公共上升子序列
    数位DP POJ3208 Apocalypse Someday
    线性DP POJ3666 Making the Grade
    杨氏矩阵 线性DP? POJ2279 Mr.Young's Picture Permutations
    tarjan强连通分量 洛谷P1262 间谍网络
    树链剖分 BZOJ3589 动态树
    二分图 BZOJ4554 [Tjoi2016&Heoi2016]游戏
  • 原文地址:https://www.cnblogs.com/sdlang/p/13083193.html
Copyright © 2011-2022 走看看