【[HNOI2017]影魔】单调栈+扫描线

本来这道题应该很简单的,越写越复杂orz

4826: [Hnoi2017]影魔

Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 912  Solved: 546 [Submit][Status][Discuss]

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]。

Input

第一行 n,m,p1,p2
第二行 n 个数:k[1],k[2],...,k[n]
接下来 m 行,每行两个数 a,b,表示询问区间[a,b]中的灵魂对会为影魔提供多少攻击力。
1 <= n,m <= 200000;1 <= p1,p2 <= 1000

Output

共输出 m 行,每行一个答案,依次对应 m 个询问。

Sample Input

10 5 2 3 7 9 5 1 3 10 6 8 2 4 1 7 1 9 1 3 5 9 1 5

Sample Output

30 39 4 13 16

HINT

Source

我们发现,对于第一种点对的贡献,就是一个点与其右边的第一个大于他的点的这样一对贡献或者一个点和于其左边第一个大于他的点的两对贡献。而第二种点对的贡献,我们记L[i]表示i左边第一个大于i的数的位置,R[i]表示i右边第一个大于i的数的位置。我们发现一个询问包含L[i]时,可以有贡献的点对,左端点L[i],右端点范围[i+1,R[i]-1],包含R[i]时,可以有贡献的点对,右端点R[i],左端点范围[L[i]+1,i-1]。我们发现第一个就是平面上一个点,而第二个就是平面上一条线段。询问[L,R]即对应一个平面上的一个正方形询问区间的包含贡献。于是我们扫描线处理一下就可以了。对于求L[i],R[i]单调栈之。 然而我很智障,写了两个算法做两个问,代码又丑又长,愿意看就看吧。
#include<stdio.h>
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
#define re return
#define int long long 

using namespace std;
const int maxn = 200005;
typedef long long ll;
struct nd{
    nd *ls,*rs; ll sm,lz,le;
}z[maxn*2],*rt; int tot,tt;
void mt(nd *&p,int l,int r){
    p = &z[++tot]; p->le=r-l+1; if(l==r) re;
    mt(p->ls,l,mid); mt(p->rs,mid+1,r);
}
void ptd(nd *&p) {
    if(!p->lz) re; p->ls->lz+=p->lz; p->rs->lz+=p->lz;
    p->ls->sm+=1ll*p->ls->le*p->lz;
    p->rs->sm+=1ll*p->rs->le*p->lz; p->lz=0;
}
void ad(nd *&p,int l,int r,int x,int y,int o){
    if(x<=l&&r<=y)  {p->sm+=1ll*p->le*o,p->lz+=o;re;} ptd(p);
    if(y>=l&&x<=mid) ad(p->ls,l,mid,x,y,o);
    if(y>mid&&x<=r) ad(p->rs,mid+1,r,x,y,o);
    p->sm=p->ls->sm+p->rs->sm;
}
ll qr(nd *&p,int l,int r,int x,int y) {
    if(x<=l&&r<=y) return p->sm; ptd(p);
    if(x>mid) return qr(p->rs,mid+1,r,x,y);
    if(y<=mid) return qr(p->ls,l,mid,x,y);
    return qr(p->ls,l,mid,x,y)+qr(p->rs,mid+1,r,x,y);
}
int n,m,p1,p2,ans[maxn],st[maxn],tp,L[maxn],R[maxn],A[maxn];




namespace ooo{

#define lowbit(x) ((x)&(-x))
ll bit[maxn];
ll gsum(int x) {
    ll sm=0; for(;x;x-=lowbit(x)) sm+=bit[x]; return sm;
}
void add(int x,int d) {
    for(;x<=n;x+=lowbit(x)) bit[x]+=d; 
}
struct oo{
    int l,r,id;
}q[maxn];
int sta[maxn],top,nt[maxn];
struct node{
    int xa,xb,y,id;
}z[maxn*3]; int tot;
bool cmp(node aa,node bb) {
    if(aa.y!=bb.y) return aa.y < bb.y;
    return aa.id < bb.id;
}
void solve() {
    sta[top=0]=n+1;A[n+1]=0x3f3f3f3f; nt[n+1]=n+1; tot=0;
    for(int i=n;i>=1;i--) {
        while(top&&A[i]>A[sta[top]]) top--;
        nt[i] = sta[top];
        sta[++top] = i;
        if(nt[i]!=n+1) {
            z[++tot] = (node){i,1,nt[i],0};
        }
    }
    for(int i=1;i<=m;i++) {
        z[++tot].xa = q[i].l; z[tot].xb = q[i].r;
        z[tot].y = q[i].l; z[tot].id = -q[i].id;
        z[++tot].xa = q[i].l; z[tot].xb = q[i].r;
        z[tot].y = q[i].r; z[tot].id = q[i].id;
    }
    sort(z+1,z+1+tot,cmp);
    for(int i=1;i<=tot;i++) {
        if(z[i].id==0) add(z[i].xa,p1);
        else if(z[i].id<0) ans[-z[i].id] -= gsum(z[i].xb) - gsum(z[i].xa-1);
        else if(z[i].id>0) ans[z[i].id] += gsum(z[i].xb) - gsum(z[i].xa-1);
    }
    for(int i=1;i<=n;i++) bit[i] = 0;
}
void mmm() {
    solve();
    reverse(A+1,A+1+n);
    for(int i=1;i<=m;i++) {
        q[i].l = n-q[i].l+1; q[i].r=n-q[i].r+1;
        swap(q[i].l,q[i].r);
    }
    solve();
}

}

struct oz{ 
    int l,r,x,iid;
}w[maxn*6]; bool cmp(oz aa,oz bb) { return aa.x!=bb.x?aa.x<bb.x:aa.iid<bb.iid; }

main(){
    scanf("%lld%lld%lld%lld",&n,&m,&p1,&p2);
    for(int i=1;i<=n;i++){
        scanf("%lld",&A[i]); while(tp&&A[i]>A[st[tp]])tp--;
        L[i] = st[tp]; st[++tp] = i;
    } st[tp=0]=n+1; mt(rt,1,n);
    
    for(int i=1;i<=m;i++) {
        int x,y; scanf("%lld%lld",&x,&y); 
        ooo::q[i].l = x; ooo::q[i].r =y; ooo::q[i].id = i;
        R[i] = st[tp];
        w[++tt].l=x; w[tt].r=y; w[tt].x=(x-1); w[tt].iid =-i;
        w[++tt].l=x; w[tt].r=y; w[tt].x=y; w[tt].iid = i;
    } 
    for(int i=n;i>0;i--) {
    while(tp&&A[i]>A[st[tp]])tp--;
        R[i] = st[tp]; st[++tp]=i;
        if(R[i]>L[i]) {
            //if(L[i]>0){ 
            w[++tt].x=L[i]; w[tt].l=i; w[tt].r=R[i];w[tt].iid=-23333333; 
            //if(R[i]<=n){
                 w[++tt].x=R[i]; w[tt].l=L[i]; w[tt].r=i;w[tt].iid=-24444444; 

        }
    }

    sort(w+1,w+1+tt,cmp);
    for(int i=1;i<=tt;i++) {
        if(w[i].iid==-23333333){ if(w[i].l+1<=w[i].r-1)ad(rt,1,n,w[i].l+1,w[i].r-1,p2); }
        else if(w[i].iid==-24444444){ if(w[i].l+1<=w[i].r-1)ad(rt,1,n,w[i].l+1,w[i].r-1,p2); }
        else {
            if(w[i].iid<0) ans[-w[i].iid]-=qr(rt,1,n,w[i].l,w[i].r);
            else 
                ans[w[i].iid]+=qr(rt,1,n,w[i].l,w[i].r);
        }
    }

    ooo::mmm();
    for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
}
 
posted @ 2018-11-27 23:59  Newuser233  阅读(9)  评论(0编辑  收藏  举报