列表

详情


NC20559. [HNOI2017]影魔

描述

影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样 的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。
每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1n
i 个灵魂的战斗力为 ,灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 来说,若不存在 大于 或者 ,则会为影魔提供 p_1 的攻击力(可理解为:当 时,因为不存在满足 s ,从 而 不存在,这时提供 p_1 的攻击力;当 时,若 , 则 提 供 p_1 的 攻 击 力 );
另 一 种 情 况 , 令 c 的最大值,若 c 满足:,或 者 ,则会为影魔提供 p_2 的攻击力,当这样的 c 不存在时,自然不会提供这 p_2 的攻击力;其他情况的点对,均不会为影魔提供攻击力。
影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任 意一段区间,位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑所有满足 的灵魂对 i,j 提供的攻击力之和。顺带一提,灵魂的战斗力组成一个 1n 的排列:

输入描述

第一行 n,m,p_1,p_2 第二行 n 个数:
接下来 m 行,每行两个数 a,b,表示询问区间 中的灵魂对会为影魔提供多少攻击力。
;

输出描述

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

示例1

输入:

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

输出:

30
39
4
13
16

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 176ms, 内存消耗: 23784K, 提交时间: 2019-10-29 22:06:44

// luogu-judger-enable-o2
//It is made by M_sea
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define re register
typedef long long ll;
using namespace std;

inline int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=200000+10;

struct Query { int x,l,r,id,v; };
struct Line { int x,l,r,v; };
bool operator <(Query a,Query b) { return a.x<b.x; }
bool operator <(Line a,Line b) { return a.x<b.x; }

int n,m,p1,p2;
int a[N],L[N],R[N];
int sta[N],top=0;
Query q[N<<1];
Line s[N*3];
ll c1[N],c2[N],ans[N];

inline int lowbit(int x) { return x&-x; }
inline void add(int x,int y) {
    if (!x) return;
    for (re int i=x;i<=n;i+=lowbit(i)) c1[i]+=y,c2[i]+=1ll*x*y;
}
inline ll sum(int x) {
    ll ans=0;
    for (re int i=x;i;i-=lowbit(i)) ans+=(x+1)*c1[i]-c2[i];
    return ans;
}

int main() {
    n=read(),m=read(),p1=read(),p2=read();
    for (re int i=1;i<=n;++i) a[i]=read();

    for (re int i=1;i<=n;++i) {
        while (top&&a[sta[top]]<a[i]) --top;
        L[i]=sta[top],sta[++top]=i;
    }
    sta[top=0]=n+1;
    for (re int i=n;i>=1;--i) {
        while (top&&a[sta[top]]<a[i]) --top;
        R[i]=sta[top],sta[++top]=i;
    }
    
    for (re int i=1;i<=m;++i) {
        int x=read(),y=read(); ans[i]+=(y-x)*p1;
        q[i]=(Query){x-1,x,y,i,-1};
        q[i+m]=(Query){y,x,y,i,1};
    }
    sort(q+1,q+m+m+1);
    
    int tot=0;
    for (re int i=1;i<=n;++i) {
        if (1<=L[i]&&R[i]<=n) s[++tot]=(Line){R[i],L[i],L[i],p1};
        if (1<=L[i]&&R[i]>i+1) s[++tot]=(Line){L[i],i+1,R[i]-1,p2};
        if (L[i]<i-1&&R[i]<=n) s[++tot]=(Line){R[i],L[i]+1,i-1,p2};
    }
    sort(s+1,s+tot+1);

    int pos1=1,pos2=1; while (!q[pos1].x) ++pos1;
    for (re int i=1;pos1<=m+m&&i<=n;++i) {
        while (pos2<=tot&&s[pos2].x<=i) {
            add(s[pos2].r+1,-s[pos2].v);
            add(s[pos2].l,s[pos2].v);
            ++pos2;
        }
        while (pos1<=m+m&&q[pos1].x<=i) {
            ans[q[pos1].id]+=q[pos1].v*(sum(q[pos1].r)-sum(q[pos1].l-1));
            ++pos1;
        }
    }
    for (re int i=1;i<=m;++i) printf("%lld\n",ans[i]);
    return 0;
}

C++(clang++11) 解法, 执行用时: 188ms, 内存消耗: 23544K, 提交时间: 2021-01-14 17:03:33

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define MAX 222222
inline int read()
{
    int x=0,t=1; char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int L[MAX],R[MAX];
int a[MAX],n,m,p1,p2;
int S[MAX],top,cnt,tot;
struct Line{int x,l,r,v;}p[MAX<<2];
bool operator<(Line a,Line b){return a.x<b.x;}
struct query{int x,l,r,v,id;}q[MAX<<2];
bool operator<(query a,query b){return a.x<b.x;}
ll c1[MAX],c2[MAX],ans[MAX];
void Modify(int x,int w)
{
	for(int i=x;i<=n;i+=i&(-i))
		c1[i]+=w,c2[i]+=x*w;
}
ll Query(int x)
{
	ll ret=0;
	for(int i=x;i;i-=i&(-i))
		ret+=(x+1)*c1[i]-c2[i];
	return ret;
}
int main()
{
	n=read();m=read();p1=read();p2=read();
	for(int i=1;i<=n;++i)a[i]=read();
	S[top=0]=0;
	for(int i=1;i<=n;++i)
	{
		while(top&&a[S[top]]<a[i])--top;
		L[i]=S[top];S[++top]=i;
	}
	S[top=0]=n+1;
	for(int i=n;i>=1;--i)
	{
		while(top&&a[S[top]]<a[i])--top;
		R[i]=S[top];S[++top]=i;
	}
	for(int i=1;i<=m;++i)
	{
		int l=read(),r=read();ans[i]=(r-l)*p1;
		q[++cnt]=(query){r,l,r,1,i};
		q[++cnt]=(query){l-1,l,r,-1,i};
	}
	sort(&q[1],&q[cnt+1]);
	for(int i=1;i<=n;++i)
	{
		if(L[i]&&R[i]<n+1)p[++tot]=(Line){R[i],L[i],L[i],p1};
		if(L[i]&&R[i]>i+1)p[++tot]=(Line){L[i],i+1,R[i]-1,p2};
		if(L[i]+1<i&&R[i]<n+1)p[++tot]=(Line){R[i],L[i]+1,i-1,p2};
	}
	sort(&p[1],&p[tot+1]);
	for(int i=1,j=1;i<=cnt;++i)
	{
		while(j<=tot&&p[j].x<=q[i].x)
		{
			Modify(p[j].l,p[j].v);
			Modify(p[j].r+1,-p[j].v);
			++j;
		}
		ans[q[i].id]+=q[i].v*(Query(q[i].r)-Query(q[i].l-1));
	}
	for(int i=1;i<=m;++i)printf("%lld\n",ans[i]);
	return 0;
}

上一题