zoukankan      html  css  js  c++  java
  • BZOJ 4826: [Hnoi2017]影魔

    4826: [Hnoi2017]影魔

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 212  Solved: 114
    [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]$和$r[i]$,分别表示$i$左边第一个比$a[i]$大的位置和右边第一个比$a[i]$大的位置...那么区间$[l[i]+1,r[i]-1]$代表的是极大的以$a[i]$为最大值的区间...

    那么点对$(l[i],r[i])$的贡献就是$p1$,$(l[i],i+1~r[i]-1)$和$(l[i]+1~i-1,r[i])$的贡献为$p2$,其他点对的贡献就是$0$了...

    欸,这就是一个区间加区间询问的问题...考试的时候写的在线,用可持久化线段树维护区间的和...但是考完发现可以离线用线段树维护...

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    //by NeighThorn
    using namespace std;
    
    const int maxn=200000+5,maxm=8000000+5;
    
    int n,m,p1,p2,top,a[maxn],lef[maxn],rig[maxn],stk[maxn];
    long long ans;
    
    struct M{
    	
    	int tot,ls[maxm],rs[maxm],root[maxn*3];
    	long long sum[maxm],add[maxm];
    	
    	inline void init(void){
    		tot=0;
    		memset(sum,0,sizeof(sum));
    		memset(root,0,sizeof(root));
    	}
    	
    	inline void change(int l,int r,int x,int &y,int L,int R,int val){
    		if(L>R) return;
    		y=++tot;sum[y]=sum[x]+(R-L+1)*val;add[y]=add[x];
    		ls[y]=ls[x];rs[y]=rs[x];
    		if(l==L&&R==r){
    			add[y]+=val;return;
    		}
    		int mid=l+r>>1;
    		if(R<=mid)
    			change(l,mid,ls[x],ls[y],L,R,val);
    		else if(L>mid)
    			change(mid+1,r,rs[x],rs[y],L,R,val);
    		else
    			change(l,mid,ls[x],ls[y],L,mid,val),change(mid+1,r,rs[x],rs[y],mid+1,R,val);
    	}
    	
    	inline long long query(int l,int r,int x,int y,int L,int R){
    		if(l==L&&r==R)
    			return sum[y]-sum[x];
    		int mid=l+r>>1;long long ans=1LL*(R-L+1)*(add[y]-add[x]);
    		if(R<=mid)
    			ans+=query(l,mid,ls[x],ls[y],L,R);
    		else if(L>mid)
    			ans+=query(mid+1,r,rs[x],rs[y],L,R);
    		else
    			ans+=query(l,mid,ls[x],ls[y],L,mid)+query(mid+1,r,rs[x],rs[y],mid+1,R);
    		return ans;
    	}
    	
    }tr1,tr2;
    
    struct N{
    	
    	int cnt,l[maxn*3],r[maxn*3],hd[maxn],val[maxn*3],nxt[maxn*3];
    	
    	inline void init(void){
    		memset(hd,-1,sizeof(hd));cnt=0;
    	}
    	
    	inline void add(int x,int L,int R,int v){
    //		cout<<x<<" "<<L<<" "<<R<<" "<<v<<endl;
    		l[cnt]=L,r[cnt]=R,val[cnt]=v,nxt[cnt]=hd[x],hd[x]=cnt++;
    	}
    	
    }tree1,tree2;
    
    inline int read(void){
    	char ch=getchar();int x=0;
    	while(!(ch>='0'&&ch<='9')) ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return x;
    }
    
    signed main(void){
    //	freopen("sf.in","r",stdin);
    //	freopen("sf.out","w",stdout);
    	n=read(),m=read(),p1=read(),p2=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	for(int i=1;i<=n;i++){
    		while(top&&a[stk[top]]<a[i]) rig[stk[top]]=i,top--;
    		stk[++top]=i;
    	}
    	while(top) rig[stk[top--]]=n+1;
    	for(int i=n;i>=1;i--){
    		while(top&&a[stk[top]]<a[i]) lef[stk[top]]=i,top--;
    		stk[++top]=i;
    	}
    	while(top) lef[stk[top--]]=0;
    	tree1.init();tree2.init();
    	for(int i=1;i<=n;i++){
    		tree1.add(lef[i],rig[i],rig[i],p1);
    		if(i+1<=rig[i]-1)
    //			cout<<"L: ",
    			tree1.add(lef[i],i+1,rig[i]-1,p2);
    		if(lef[i]+1<=i-1)
    //			cout<<"R: ",
    			tree2.add(rig[i],lef[i]+1,i-1,p2);
    	}
    //	puts("finish prework");
    	tr1.init();tr2.init();
    	for(int x=1;x<=n;x++){
    		tr1.root[x]=tr1.root[x-1];
    		for(int i=tree1.hd[x];i!=-1;i=tree1.nxt[i])
    //			cout<<"L: "<<x<<" "<<tree1.l[i]<<" "<<tree1.r[i]<<" "<<tree1.val[i]<<endl,
    			tr1.change(1,n,tr1.root[x],tr1.root[x],max(1,tree1.l[i]),min(n,tree1.r[i]),tree1.val[i]);
    	}
    	for(int x=n;x>=1;x--){
    		tr2.root[x]=tr2.root[x+1];
    		for(int i=tree2.hd[x];i!=-1;i=tree2.nxt[i])
    //			cout<<"R: "<<x<<" "<<tree2.l[i]<<" "<<tree2.r[i]<<" "<<tree2.val[i]<<endl,
    			tr2.change(1,n,tr2.root[x],tr2.root[x],max(1,tree2.l[i]),min(n,tree2.r[i]),tree2.val[i]);
    	}
    	for(int i=1,x,y;i<=m;i++){
    		x=read(),y=read();ans=(y-x)*p1;
    		ans+=tr1.query(1,n,tr1.root[x-1],tr1.root[y],x,y);
    		ans+=tr2.query(1,n,tr2.root[y+1],tr2.root[x],x,y);
    		printf("%lld
    ",ans);
    	}
    //	fclose(stdin);fclose(stdout);
    	return 0;
    }
    

      


    By NeighThorn

  • 相关阅读:
    <Redis> 入门六 主从复制方式的集群
    <Redis> 入门五 持久化RBD/AOF
    <Redis> 入门四 Jedis操作Redis
    <Redis> 入门三 事务
    <Redis> 入门X 分布式锁
    <Redis> 入门二 五种数据类型的操作、通用key的操作、发布订阅
    <Redis> 入门一 概念安装
    <Linux> 下安装和卸载JDK
    <ActiveMQ>
    <linux>入门
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6735705.html
Copyright © 2011-2022 走看看