• BZOJ4826: [Hnoi2017]影魔


    BZOJ4826: [Hnoi2017]影魔

    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

    题解Here!
    我们发现要处理一堆区间$emmm...$
    话说这题能不能用区间神器莫队呢?
    好像不能欸,因为我没有想出来区间和值不好转变。
    我们发现对于$p_1$类型的区间$[i,j]$。
    如果$j>i$那么$j$一定是$i$右侧第一个比它大的点。
    什么?$j<i$?,反转区间可以转化成情况一。
    再考虑$p_2$情况类型的区间$[i,j]$
    如果$i$小于$j$,则$i$一定是这样的点:它在区间$(p,q)$之间
    $(p,q)$是开区间!!!
    其中$[q.j]$是一个$p_1$类型的区间,$p$是$q$左侧第一个比q大的点。
    同理$i>j$是可以反转区间转换为情况一。
    通过反证法我们可以很容易的证明上面的说法可以不重不漏的
    枚举出所有的$p_1,p_2$(假设有一个不符合条件的区间,发现很快就会出矛盾)。
    发现上述一套花里胡哨的定义只需要两个信息:
    点$i$左侧第一个比他大的点是谁;
    点$i$右侧第一个比他大的点是谁。
    这。。。当然单调栈$O(n)$预处理啊。。。
    接下来是统计区间。
    发现在线处理会直接晕掉,考虑离线处理。。。
    把询问按右端点排序,之后每次拓展右端点。
    更新所有合法的左端点即可。
    然后我们发现$p_1$是单点修改,$p_2$是区间修改。
    结果一堆大佬直接树状数组。。。
    本蒟蒻表示根本不会。。。
    于是直接上线段树。。。
    然后线段树求一下就是结果了。
    $BUT$!上述只处理了一半,即$i$小于$j$。
    那另外一半呢?
    我们可以把区间和询问统统反转,处理下一半情况。
    细节看代码吧,不看代码刚才讲的好多细节没有。。。
    附代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define LSON rt<<1
    #define RSON rt<<1|1
    #define DATA(x) a[x].data
    #define SIGN(x) a[x].c
    #define LSIDE(x) a[x].l
    #define RSIDE(x) a[x].r
    #define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
    #define MAXN 200010
    using namespace std;
    int n,m,top;
    int next[MAXN],stack[MAXN];
    long long p1,p2,val[MAXN],ans[MAXN];
    struct Sg_Tree{
    	long long data,c;
    	int l,r;
    }a[MAXN<<2];
    struct node{
    	int l,r,id;
    }que[MAXN];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    bool cmp(const node &x,const node &y){
    	if(x.l==y.l)return x.r<y.r;
    	return x.l<y.l;
    }
    inline void pushup(int rt){
    	DATA(rt)=DATA(LSON)+DATA(RSON);
    }
    inline void pushdown(int rt){
    	if(!SIGN(rt)||LSIDE(rt)==RSIDE(rt))return;
    	SIGN(LSON)+=SIGN(rt);
    	DATA(LSON)+=SIGN(rt)*WIDTH(LSON);
    	SIGN(RSON)+=SIGN(rt);
    	DATA(RSON)+=SIGN(rt)*WIDTH(RSON);
    	SIGN(rt)=0;
    }
    void buildtree(int l,int r,int rt){
    	int mid;
    	LSIDE(rt)=l;
    	RSIDE(rt)=r;
    	SIGN(rt)=0;
    	if(l==r){
    		DATA(rt)=0;
    		return;
    	}
    	mid=l+r>>1;
    	buildtree(l,mid,LSON);
    	buildtree(mid+1,r,RSON);
    	pushup(rt);
    }
    void update(int l,int r,long long c,int rt){
    	int mid;
    	if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
    		SIGN(rt)+=c;
    		DATA(rt)+=c*WIDTH(rt);
    		return;
    	}
    	pushdown(rt);
    	mid=LSIDE(rt)+RSIDE(rt)>>1;
    	if(l<=mid)update(l,r,c,LSON);
    	if(mid<r)update(l,r,c,RSON);
    	pushup(rt);
    }
    long long query(int l,int r,int rt){
    	int mid;
    	long long ans=0;
    	if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
    	pushdown(rt);
    	mid=LSIDE(rt)+RSIDE(rt)>>1;
    	if(l<=mid)ans+=query(l,r,LSON);
    	if(mid<r)ans+=query(l,r,RSON);
    	return ans;
    }
    int half_find(int x){
    	int left=1,right=m+1,mid;
    	while(left<=right){
    		mid=left+right>>1;
    		if(que[mid].l<x)left=mid+1;
    		else right=mid-1;
    	}
    	return left;
    }
    void work(){
    	top=0;
    	stack[top]=n+1;
    	buildtree(1,n+1,1);
    	for(int i=n;i>=1;i--){
    		while(top&&val[stack[top]]<val[i])stack[top--]=0;
    		next[i]=stack[top];
    		stack[++top]=i;
    	}
    	for(int i=n;i>=1;i--){
    		if(next[i]>i){
    			update(i+1,next[i],p2,1);
    			update(next[i],next[i],p1-p2*2,1);
    		}
    		int pos=half_find(i);
    		while(que[pos].l==i){
    			ans[que[pos].id]+=query(i+1,que[pos].r,1);
    			pos++;
    		}
    	}
    }
    void init(){
    	n=read();m=read();p1=read();p2=read();
    	for(int i=1;i<=n;i++)val[i]=read();
    	for(int i=1;i<=m;i++){
    		que[i].l=read();que[i].r=read();
    		que[i].id=i;
    	}
    	sort(que+1,que+m+1,cmp);
    	work();
    	for(int i=1;i<=n/2;i++)swap(val[i],val[n-i+1]);
    	for(int i=1;i<=m;i++){
    		swap(que[i].l,que[i].r);
    		que[i].l=n-que[i].l+1;
    		que[i].r=n-que[i].r+1;
    	}
    	sort(que+1,que+m+1,cmp);
    	work();
    	for(int i=1;i<=m;i++)printf("%lld
    ",ans[i]);
    }
    int main(){
    	init();
    	return 0;
    }
    
  • 相关阅读:
    Oracle跟踪生成及Tkprof分析性能实战(附实战Demo)系列一
    sqlserver查看锁及解锁
    ETL利器Kettle实战应用解析系列二 【应用场景和实战DEMO下载】
    利用反射从程序集dll中动态调用方法(附demo下载)
    ETL利器Kettle实战应用解析系列三 【ETL后台进程执行配置方式】
    分享一款Web压力测试工具Pylot
    stark组件前戏之以上知识点整合应用示例
    rbac组件权限分配
    rbac组件权限分配之权限批量操作
    stark组件开发之自动生成URL
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9464948.html
Copyright © 2020-2023  润新知