• 【BZOJ4826】【HNOI2017】影魔(扫描线,单调栈)


    【BZOJ4826】【HNOI2017】影魔(扫描线,单调栈)

    题面

    BZOJ
    洛谷

    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

    题解

    这题和序列很类似
    但是我依然不是自己做出来的
    还是太弱了


    首先把两种贡献换成人话:
    如果对于两个位置(l,r)
    他们是区间([l,r])中的最大值和次大值,产生(p1)的贡献
    如果恰好有一个是最大值,产生(p2)的贡献

    那么,对于当前位置(i),假设左/右第一个比他大的位置是(l,r)
    那么,((l,r))产生(p1)的贡献
    ((l+1..i-1,r),(l,i+1..r-1))会产生(p2)的贡献
    可以把他分解为二维平面内的矩阵求和问题,这个可以用扫描线来解决

    当然,主要的问题是怎么转换为二维平面求矩阵和。。。

    我们算的是当前加上了位置(i)以后产生的贡献
    如果对于一个询问(L,R)(i)在其范围内,当然就要考虑它产生的贡献
    那么,(i)产生的贡献是什么?
    就是我们前面考虑过的问题
    将一个位置(i)拆分成(3)个贡献:
    当加入完位置(R[i])之后,要对于(L[i])产生(p1)的贡献
    当加入完位置(L[i])之后,要对于((i,R[i]))的每个位置产生(p2)的贡献
    当加入完位置(R[i])之后,要对于((L[i],i))的每个位置产生(p2)的贡献

    那么,一个询问(L,R),只要考虑它范围内的贡献
    因此拆分成三部分
    加入完(L-1)位置之后,要忽略掉前面所有(L,R)位置产生的贡献
    加入完(R)位置之后,要考虑所有的(L,R)位置产生的贡献
    额外考虑每一组范围内的,((i,i+1))产生的贡献(p1)

    这样子,扫描线+区间加法+区间求和即可
    可以用单调栈+树状数组实现。

    #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 RG register
    #define MAX 222222
    inline int read()
    {
        RG int x=0,t=1;RG 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
    ",ans[i]);
    	return 0;
    }
    
    
  • 相关阅读:
    配置apache的文件访问路径
    php 常量const
    php接口interface的使用
    php 抽象类abstract
    php 面向对象三大特点:封装、继承、多态
    程序员的情怀《从前慢》木心
    php static静态属性和静态方法
    php面向对象的构造方法与析构方法
    关于php变量的赋值和引用的区别
    angular4.0微信oAuth第三方认证的正确方式
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8688783.html
Copyright © 2020-2023  润新知