[BZOJ 4826][Hnoi2017]影魔(主席树)

Description

影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样
的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。每一个灵魂,都有着自己的战斗力,而影魔,靠
这些战斗力提升自己的攻击。奈文摩尔有 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]。

Solution

单调栈可求出位置i左边第一个比它大的位置L[i]和右边第一个比它大的位置R[i]

可以知道点对(L[i],R[i])提供p1的攻击力

L[i]+1~i-1与R[i]组成的点对提供p2的攻击力

L[i]与i+1~R[i]-1组成的点对提供p2的攻击力

于是用主席树维护,新加入一个点作为左端点或右端点时的攻击力

还要加上相邻的每两个点对的攻击力p1

WA调了好久,还怀疑是有些地方没开LL,后来发现是数组越界了…开大一点就好了//话说为什么不是RE

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 200005
#define INF 0x3f3f3f3f
typedef long long LL;
using namespace std;
int n,m,p1,p2,k[MAXN];
int s[MAXN],top,L[MAXN],R[MAXN],head1[MAXN],cnt1=0,head2[MAXN],cnt2=0;
struct Node
{
    int l,r,w,next;
}x[MAXN*4],y[MAXN*4];
void add1(int u,int l,int r,int w)
{
    x[++cnt1].next=head1[u];
    head1[u]=cnt1;
    x[cnt1].l=l,x[cnt1].r=r,x[cnt1].w=w;
}
void add2(int u,int l,int r,int w)
{
    y[++cnt2].next=head2[u];
    head2[u]=cnt2;
    y[cnt2].l=l,y[cnt2].r=r,y[cnt2].w=w;
}
struct fotile_tree
{
    int rt[MAXN],ls[MAXN*50],rs[MAXN*50],tot;
    LL atk[MAXN*50],val[MAXN*50];
    fotile_tree(){tot=0;}
    void build(int &idx,int l,int r)
    {
        ++tot,idx=tot;
        atk[idx]=val[idx]=0;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(ls[idx],l,mid);
        build(rs[idx],mid+1,r);
    }
    void insert(int &idx,int last,int l,int r,int x,int y,int v)
    {
        if(x>y)return;
        ++tot,idx=tot;
        atk[idx]=atk[last]+1LL*(y-x+1)*v,val[idx]=val[last];
        ls[idx]=ls[last],rs[idx]=rs[last];
        if(l==x&&r==y){val[idx]+=v;return;}
        int mid=(l+r)>>1;
        if(y<=mid)insert(ls[idx],ls[last],l,mid,x,y,v);
        else if(x>mid)insert(rs[idx],rs[last],mid+1,r,x,y,v);
        else {insert(ls[idx],ls[last],l,mid,x,mid,v);insert(rs[idx],rs[last],mid+1,r,mid+1,y,v);}
    }
    LL query(int s,int t,int l,int r,int x,int y)
    {
        if(x>y)return 0; 
        if(l==x&&r==y)return atk[t]-atk[s];
        int mid=(l+r)>>1;
        LL calc=1LL*(y-x+1)*(val[t]-val[s]);
        if(y<=mid){return calc+query(ls[s],ls[t],l,mid,x,y);}
        else if(x>mid)return calc+query(rs[s],rs[t],mid+1,r,x,y);
        else return calc+query(ls[s],ls[t],l,mid,x,mid)+query(rs[s],rs[t],mid+1,r,mid+1,y);
    }
}trL,trR;
int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=-1;c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';c=getchar();
    }
    return x*f;
}
int main()
{
    memset(head1,-1,sizeof(head1));
    memset(head2,-1,sizeof(head2));
    n=read(),m=read(),p1=read(),p2=read();
    for(int i=1;i<=n;i++)k[i]=read();
    top=0;
    for(int i=1;i<=n;i++)
    {
        while(top&&k[s[top]]<k[i])R[s[top]]=i,top--;
        s[++top]=i;
    }
    while(top)R[s[top]]=n+1,top--;
    top=0;
    for(int i=n;i>0;i--)
    {
        while(top&&k[s[top]]<k[i])L[s[top]]=i,top--;
        s[++top]=i;
    }
    while(top)L[s[top]]=0,top--;
    for(int i=1;i<=n;i++)
    {
        add1(L[i],R[i],R[i],p1);
        add1(L[i],i+1,R[i]-1,p2);
        add2(R[i],L[i]+1,i-1,p2);
    }
    trL.build(trL.rt[0],1,n);trR.build(trR.rt[n+1],1,n);
    for(int i=1;i<=n;i++)
    {
        trL.rt[i]=trL.rt[i-1];
        for(int j=head1[i];~j;j=x[j].next)
        trL.insert(trL.rt[i],trL.rt[i],1,n,max(1,x[j].l),min(n,x[j].r),x[j].w);
    }
    for(int i=n;i>0;i--)
    {
        trR.rt[i]=trR.rt[i+1];
        for(int j=head2[i];~j;j=y[j].next)
        trR.insert(trR.rt[i],trR.rt[i],1,n,max(1,y[j].l),min(n,y[j].r),y[j].w);
    }
    for(int i=1;i<=m;i++)
    {
        int a=read(),b=read();
        if(a>b)swap(a,b); 
        LL ans=1LL*(b-a)*p1;
        ans+=trL.query(trL.rt[a-1],trL.rt[b],1,n,a,b);
        ans+=trR.query(trR.rt[b+1],trR.rt[a],1,n,a,b);
        printf("%lld\n",ans);
    }
    return 0;
} 

 

posted @ 2017-04-30 01:33  Zars19  阅读(250)  评论(0编辑  收藏  举报