HNOI2017影魔

题目链接

单调栈&线段树

离线处理询问,首先用单调栈预处理出左边第一个大于它的数head[i]及右边第一个大于它的数tail[i],然后从左到右及从右到左各进行一遍下述操作:

从右到左枚举一个点i,作为区间的左端点,然后对于i+1到tail[i]在线段树中全部加上p2,若tail[i]不等于n+1就把tail[i]加上p1-2*p2 (因为[i,tail[i]]这个区间是要加上p1的,而正反各做一次却加上了两个p2) 。

若有一个以i为左端点的询问,则把这个询问的答案加上1~询问右端点的和。可以自己举几个例子,发现这样是可以处理到每一个区间对答案的贡献的。

复杂度O(nlogn)。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<bitset>
#include<cmath>
#define P puts("lala")
#define pc cerr<<"lala"<<endl
#define HH puts("")
#define pb push_back
#define pf push_front
#define fi first
#define se second 
#define mkp make_pair
using namespace std;
inline void read(int &re)
{
    char ch=getchar();int g=1;
    while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
    re=0;
    while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
    re*=g;
}
typedef long long ll;
inline void read(ll &re)
{
    char ch=getchar();ll g=1;
    while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
    re=0;
    while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+ch-48ll,ch=getchar();
    re*=g;
}
const int N=200050;
int n,m,p1,p2;
int att[N];
int st[N],top=0;
int add[N<<2],head[N],tail[N];
ll sum[N<<2];

inline void pushdown(int o,int l,int r)
{
    if(add[o])
    {
        add[o<<1]+=add[o];add[o<<1|1]+=add[o];
        int mid=l+r>>1;
        sum[o<<1]+=(ll)(mid-l+1)*add[o];sum[o<<1|1]+=(ll)(r-mid)*add[o];
        add[o]=0;
    }    
}

void update(int o,int l,int r,int x,int y,int k)
{
    if(x<=l&&r<=y)
    {
        add[o]+=k;
        sum[o]+=(ll)(r-l+1)*k;
        return ;
    }
    pushdown(o,l,r);
    int mid=l+r>>1;
    if(x<=mid) update(o<<1,l,mid,x,y,k);
    if(y>mid) update(o<<1|1,mid+1,r,x,y,k);
    sum[o]=sum[o<<1]+sum[o<<1|1];
}

ll query(int o,int l,int r,int x,int y)
{
    if(x<=l&&r<=y) return sum[o];
    pushdown(o,l,r);
    int mid=l+r>>1;
    ll ans=0;
    if(x<=mid) ans+=query(o<<1,l,mid,x,y);
    if(y>mid) ans+=query(o<<1|1,mid+1,r,x,y);
    sum[o]=sum[o<<1]+sum[o<<1|1];
    return ans;
}

struct node
{
    int l,r;
    ll ans;
}qr[N];
bool cmp1(node a,node b)
{
    return a.l<b.l;
}
bool cmp2(node a,node b)
{
    return a.r>b.r;
}

vector<int>ve1[N],ve2[N];

int main()
{
#ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);freopen("1.out","w",stdout);
#endif
    int i,j,opt,T;
    read(n);read(m);read(p1);read(p2);
    for(i=1;i<=n;++i) read(att[i]);
    for(i=n;i;--i)
    {
        if(!top) st[++top]=i;
        else
        {
            while(top&&att[st[top]]<att[i]) top--;
            if(top) tail[i]=st[top];
            st[++top]=i;
        }
    }
    memset(st,0,sizeof(st));
    top=0;

    for(i=1;i<=n;++i)
    {
        if(!top) st[++top]=i;
        else
        {
            while(top&&att[st[top]]<att[i]) top--;
            if(top) head[i]=st[top];
            st[++top]=i;
        }
    }
    
    for(i=1;i<=m;++i)
    {
        read(qr[i].l);read(qr[i].r);
        ve1[qr[i].l].pb(i);ve2[qr[i].r].pb(i);
        qr[i].ans=0;
    }

    for(i=1;i<=n;++i)
    {
        j=(head[i]?head[i]:1);
        if(j!=i) update(1,1,n,j,i-1,p2);
        if(head[i]) update(1,1,n,head[i],head[i],p1-2*p2);
        int siz=ve2[i].size();
        for(int o=0;o<siz;++o)
        {
            int u=ve2[i][o];
            qr[u].ans+=query(1,1,n,qr[u].l,n);
        }
    }

    memset(add,0,sizeof(add));memset(sum,0,sizeof(sum));

    for(i=n;i;--i)
    {
        j=(tail[i]?tail[i]:n);
        if(j!=i) update(1,1,n,i+1,j,p2);
        if(tail[i]) update(1,1,n,tail[i],tail[i],p1-2*p2);
        int siz=ve1[i].size();
        for(int o=0;o<siz;++o)
        {
            int u=ve1[i][o];
            qr[u].ans+=query(1,1,n,1,qr[u].r);
        }
    }

    for(i=1;i<=m;++i) printf("%lld
",qr[i].ans);
    return 0;
}
/*

*/
原文地址:https://www.cnblogs.com/thkkk/p/7837369.html