[HNOI2017/AHOI2017]影魔

Description:

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

Hint:

对于 (30\%) 的数据,(1le n, mle 500)
另有 (30\%) 的数据,(p_1 = 2p_2)
对于 (100\%) 的数据,(1le n,mle 200000, 1le p_1, p_2le 1000)

Solution:

这题直接统计不好统计

我们反过来考虑每个位置对区间的贡献

首先预处理出每个位置左右第一个大于它的位置

1.(i​)对于区间((l[i] ,r[i]​)),有(p_1​)的贡献,我们在扫到(r[i]​)更新(l[i]​)即可

2.(i)对于所有区间((l[i],i+1 ext{~} r[i]-1))(p_2)的贡献,我们在扫到(l[i])时更新(i+1 ext{~} r[i]-1)

3.(i​)对于所有区间((l[i]+1 ext{~}i-1,r[i])​)(p_2​)的贡献,我们在扫到(r[i]​)时更新(l[i]+1 ext{~}i-1​)

然后把询问离线拆成(l,r)后按端点排序,每次询问区间(l~r)的和,答案就是两次询问相减

注意要特判相邻位置的贡献

update:
今天体育课ysbs给我讲了一个更优秀的方法,实际上没必要处理出每个点的左右边界
对于贡献2,我们只要枚举所有以该点为右端点的区间,单调栈维护最近的大于该点的位置
分为左大于右和左小于右两种情况分别做一次就行,这样稍微方便一些

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1 
#define rs p<<1|1
using namespace std;
typedef long long ll;
const ll mxn=1e6+5;
ll n,m,p1,p2,tot,cnt1,cnt2,a[mxn],lt[mxn],rt[mxn],ans[mxn];
ll hd1[mxn],hd2[mxn],tr[mxn<<2],tag[mxn<<2];

struct Q {
    ll pos,l,r,id;	
}q[mxn];

struct ed {
    ll to1,to2,nxt;
}t1[mxn],t2[mxn];

inline ll read() {
    char c=getchar(); ll x=0,f=1;
    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
    return x*f;
}
inline ll chkmax(ll &x,ll y) {if(x<y) x=y;}
inline ll chkmin(ll &x,ll y) {if(x>y) x=y;}

ll cmp(Q x,Q y) {
    return x.pos<y.pos;
}

inline void add1(ll u,ll v) {
    t1[++cnt1]=(ed) {v,0,hd1[u]};
    hd1[u]=cnt1;
}

inline void add2(ll u,ll v,ll w) {
    t2[++cnt2]=(ed) {v,w,hd2[u]};
    hd2[u]=cnt2;
}

void push_up(ll p) {
    tr[p]=tr[ls]+tr[rs];
}

void push_down(ll l,ll r,ll p) {
    if(tag[p]) {
        ll mid=(l+r)>>1;
        tr[ls]+=(mid-l+1)*tag[p];
        tr[rs]+=(r-mid)*tag[p];
        tag[ls]+=tag[p];
        tag[rs]+=tag[p];
        tag[p]=0;
    }
}

void update1(ll l,ll r,ll pos,ll val,ll p)
{
    if(l==r) {
        tr[p]+=val;
        return ;
    }
    ll mid=(l+r)>>1; push_down(l,r,p);
    if(pos<=mid) update1(l,mid,pos,val,ls); 
    else update1(mid+1,r,pos,val,rs);
    push_up(p);
}

void update2(ll l,ll r,ll ql,ll qr,ll val,ll p)
{
    if(ql<=l&&r<=qr) {
        tr[p]+=val*(r-l+1);
        tag[p]+=val;
        return ;
    }
    ll mid=(l+r)>>1; push_down(l,r,p);
    if(ql<=mid) update2(l,mid,ql,qr,val,ls);
    if(qr>mid) update2(mid+1,r,ql,qr,val,rs);
    push_up(p);
}

ll query(ll l,ll r,ll ql,ll qr,ll p)
{
    if(ql<=l&&r<=qr) return tr[p];
    ll mid=(l+r)>>1; push_down(l,r,p); ll res=0;
    if(ql<=mid) res+=query(l,mid,ql,qr,ls);
    if(qr>mid) res+=query(mid+1,r,ql,qr,rs);
    return res;
}

int main()
{
    n=read(); m=read(); p1=read(); p2=read(); ll l,r;
    for(ll i=1;i<=n;++i) a[i]=read();
    for(ll i=1;i<=m;++i) {
        l=read(),r=read();
        q[i]=(Q){l-1,l,r,i};
        q[i+m]=(Q){r,l,r,i+m};
    }
    stack<ll > st;
    for(ll i=1;i<=n;++i) {
        while(!st.empty()&&a[st.top()]<a[i]) st.pop(); 
        if(st.empty()) lt[i]=0;
        else lt[i]=st.top(); st.push(i);
    }
    while(!st.empty()) st.pop();
    for(ll i=n;i>=1;--i) {
        while(!st.empty()&&a[st.top()]<a[i]) st.pop();
        if(st.empty()) rt[i]=n+1;
        else rt[i]=st.top(); st.push(i);
        if(lt[i]+1!=rt[i]) add1(rt[i],lt[i]); 
        add2(rt[i],lt[i]+1,i-1); add2(lt[i],i+1,rt[i]-1); 
    }
    sort(q+1,q+2*m+1,cmp); ll pos=0;
    for(ll i=1;i<=2*m;++i) {
        while(pos<q[i].pos) {
            ++pos; if(pos-1!=0) update1(1,n,pos-1,p1,1);
            for(ll j=hd1[pos];j;j=t1[j].nxt) {
                ll v=t1[j].to1;
                if(v!=0) update1(1,n,v,p1,1);
            }
            for(ll j=hd2[pos];j;j=t2[j].nxt) {
                ll v=t2[j].to1,w=t2[j].to2;
                if(v!=0&&w!=0&&w!=n+1&&v!=n+1) update2(1,n,v,w,p2,1);
            }
        } 
        l=q[i].l; r=q[i].r;
        ans[q[i].id]=query(1,n,l,r,1);
    }
    for(ll i=1;i<=m;++i) printf("%lld
",ans[i+m]-ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/list1/p/10520711.html