[bzoj4826][Hnoi2017]影魔

来自FallDream的博客,未经允许,请勿转载,谢谢。


 

影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n。第 i个灵魂的战斗力为 k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 i,j(i<j)来说,若不存在 k[s](i<s<j)大于 k[i]或者 k[j],则会为影魔提供 p1 的攻击力(可理解为:当 j=i+1 时,因为不存在满足 i<s<j 的 s,从而 k[s]不存在,这时提供 p1 的攻击力;当 j>i+1 时,若max{k[s]|i<s<j<=min{k[i],k[j]} , 则 提 供 p1 的 攻击力 ); 另 一 种 情 况 , 令 c 为k[i+1],k[i+2],k[i+3]......k[j-1]的最大值,若 c 满足:k[i]<c<k[j],或
者 k[j]<c<k[i],则会为影魔提供 p2 的攻击力,当这样的 c 不存在时,自然不会提供这 p2 的攻击力;其他情况的点对,均不会为影魔提供攻击力。影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任意一段区间[a,b],1<=a<b<=n,位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑 所有满足a<=i<j<=b 的灵魂对 i,j 提供的攻击力之和。顺带一提,灵魂的战斗力组成一个 1 到 n 的排列:k[1],k[2],...,k[n]。
n,m<=2*10^5
 
题面剧毒...看错了几次
考虑枚举中间那一段的最值是啥,那么对于每个枚举的值,显然需要找到的是左右第一个大于它的。这个可以单调栈实现。
然后假设左右两边第一个大于它的是l,r 那么
l和r贡献p1
[l+1,i-1]和r贡献p2
l和[i+1,r-1]贡献p3
另外 对于每个i<n  i和i+1有贡献p1
查询可以看作是查矩形  修改是改线段 那么主席树维护即可。
复杂度nlogn
#include<iostream>
#include<cstdio>
#include<vector>
#define MN 200000
#define ll long long
#define getchar() (*S++)
char B[1<<26],*S=B;
using namespace std;
inline int read()
{
    int x = 0; char ch = getchar();
    while(ch < '0' || ch > '9')ch = getchar();
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x;
}

int a[MN+5],n,m,p1,p2,cnt=0,L[MN+5],R[MN+5],rt[MN+5];
struct Tree{int l,r,x;ll val;}T[MN*80];
struct data{int l,r,x;};
vector<data> v[MN+5];
struct MyQue
{
    int q[MN+5],top;
    void clear(int x){q[top=0]=x;}
    int ins(int i)
    {
        while(top&&a[q[top]]<a[i]) --top;
        int ret=q[top];
        q[++top]=i;
        return ret;
    }
}Q;

inline int NewNode(int x){T[++cnt]=T[x];return cnt;}

ll Query(int x,int l,int r,int lt,int rt)
{
    if(l==lt&&r==rt) return T[x].val;
    int mid=lt+rt>>1;ll sum=1LL*(r-l+1)*T[x].x;
    if(r<=mid) return sum+Query(T[x].l,l,r,lt,mid);
    else if(l>mid) return sum+Query(T[x].r,l,r,mid+1,rt);
    else return sum+Query(T[x].l,l,mid,lt,mid)+Query(T[x].r,mid+1,r,mid+1,rt);
}

void Modify(int x,int l,int r,int lt,int rt,int ad)
{
    T[x].val+=1LL*(r-l+1)*ad;
    if(l==lt&&r==rt)
    {
        T[x].x+=ad;
        return;
    }
    int mid=lt+rt>>1;
    if(r<=mid) Modify(T[x].l=NewNode(T[x].l),l,r,lt,mid,ad);
    else if(l>mid) Modify(T[x].r=NewNode(T[x].r),l,r,mid+1,rt,ad);
    else Modify(T[x].l=NewNode(T[x].l),l,mid,lt,mid,ad),
         Modify(T[x].r=NewNode(T[x].r),mid+1,r,mid+1,rt,ad);
}

int main()
{
    fread(B,1,1<<26,stdin);
    n=read();m=read();p1=read();p2=read();
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=1;i<=n;++i) L[i]=Q.ins(i);
    Q.clear(n+1);
    for(int i=n;i;--i) R[i]=Q.ins(i);
    for(int i=1;i<=n;++i)
    {
        if(i<n) v[i].push_back((data){i+1,i+1,p1});
        if(L[i]&&R[i]<=n) v[L[i]].push_back((data){R[i],R[i],p1});
        if(L[i]&&i<=R[i]-2) v[L[i]].push_back((data){i+1,R[i]-1,p2});
        if(R[i]<=n&&i>=L[i]+2) v[R[i]].push_back((data){L[i]+1,i-1,p2});
    }
    for(int i=1;i<=n;++i)
    {
        rt[i]=rt[i-1];
        for(int j=0;j<v[i].size();++j)
            Modify(rt[i]=NewNode(rt[i]),v[i][j].l,v[i][j].r,1,n,v[i][j].x);
    }
    for(int i=1;i<=m;++i)
    {
        int l=read(),r=read();
        printf("%lld\n",Query(rt[r],l,r,1,n)-Query(rt[l-1],l,r,1,n));
    }
    return 0;
}
posted @ 2017-05-17 23:12  FallDream  阅读(641)  评论(0编辑  收藏  举报