BZOJ 4826 【HNOI2017】 影魔

题目链接:影魔

  这道题就是去年序列的弱化版啊……

  我们枚举最大值的位置\(i\),找出左边第一个比\(a_i\)大的位置\(l\),右边第一个比\(a_i\)大的位置\(r\),然后我们分开考虑一下\(p_1\)和\(p_2\)的贡献。

  首先由于\(a_i\)为最大值,那么左端点不会小于\(l\),右端点不会大于\(r\)。

  容易发现只有左端点为\(l\),右端点为\(r\)才会产生\(p_1\)的贡献。

  然后产生\(p_2\)贡献的有两种:一种是左端点为\(l\),右端点在区间\((i,r)\)中;另一种是左端点区间\((l,i)\)中,右端点为\(r\)。

  所以这个问题可以抽象到二维平面上。有一些点和一些线段都有权值,每次询问某个矩形内部的权值和。

  于是离线排序+扫描线+树状数组即可。

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 200010

using namespace std;
typedef long long llg;

struct Segment{
	int l,r,x,b,z;
	bool operator < (const Segment &h)const{return x<h.x;}
}s1[maxn<<1],s2[maxn*3];
int n,m,p1,p2,S[maxn],top,ls;
int a[maxn],le[maxn],ri[maxn];
llg ans[maxn],c1[maxn],c2[maxn];

int getint(){
	int w=0;bool q=0;
	char c=getchar();
	while((c>‘9‘||c<‘0‘)&&c!=‘-‘) c=getchar();
	if(c==‘-‘) c=getchar(),q=1;
	while(c>=‘0‘&&c<=‘9‘) w=w*10+c-‘0‘,c=getchar();
	return q?-w:w;
}

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

int main(){
	File("sf");
	n=getint(),m=getint(),p1=getint(),p2=getint();
	for(int i=1;i<=n;i++) a[i]=getint();
	a[0]=a[n+1]=n+1; S[top=1]=0;
	for(int i=1;i<=n;i++){
		while(a[S[top]]<a[i]) top--;
		le[i]=S[top]; S[++top]=i;
	}
	S[top=1]=n+1;
	for(int i=n;i>=1;i--){
		while(a[S[top]]<a[i]) top--;
		ri[i]=S[top]; S[++top]=i;
	}
	for(int i=1,l,r;i<=m;i++){
		l=getint(),r=getint(); ans[i]+=1ll*(r-l)*p1;
		s1[i].l=l,s1[i].r=r,s1[i].x=l-1;
		s1[i].b=i,s1[i].z=-1; s1[i+m]=s1[i];
		s1[i+m].x=r,s1[i+m].z=1;
	}
	sort(s1+1,s1+m*2+1);
	for(int i=1;i<=n;i++){
		if(le[i] && ri[i]<=n){
			ls++; s2[ls].x=ri[i]; s2[ls].z=p1;
			s2[ls].l=s2[ls].r=le[i];
		}
		if(le[i] && ri[i]>i+1){
			ls++; s2[ls].x=le[i]; s2[ls].z=p2;
			s2[ls].l=i+1,s2[ls].r=ri[i]-1;
		}
		if(ri[i]<=n && i>le[i]+1){
			ls++; s2[ls].x=ri[i]; s2[ls].z=p2;
			s2[ls].l=le[i]+1,s2[ls].r=i-1;
		}
	}
	sort(s2+1,s2+ls+1); int n1=1,n2=1;
	while(!s1[n1].x) n1++;
	for(int i=1;n1<=m*2 && i<=n;i++){
		while(n2<=ls && s2[n2].x==i){
			add(s2[n2].r+1,-s2[n2].z);
			add(s2[n2].l,s2[n2].z),n2++;
		}
		while(n1<=m*2 && s1[n1].x==i){
			ans[s1[n1].b]+=s1[n1].z*(sum(s1[n1].r)-sum(s1[n1].l-1));
			n1++;
		}
	}
	for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
	return 0;
}
时间: 2024-10-08 08:15:59

BZOJ 4826 【HNOI2017】 影魔的相关文章

[BZOJ4826][HNOI2017]影魔(主席树)

4826: [Hnoi2017]影魔 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 669  Solved: 384[Submit][Status][Discuss] Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样 的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己的战斗力,而影魔,靠 这些战斗力提升自己的攻击.奈文摩尔有 n 个

AC日记——[Hnoi2017]影魔 bzoj 4826

4826 思路: 主席树矩阵加减+单调栈预处理: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 200005 #define ll long long #define maxtree maxn*30 class PTreeType { private: int ch[maxtree][2],root[maxn],tot,head[maxn],li[maxn<<1],ri[maxn<<1],E

[BZOJ 4826]影魔 区间修改主席树 标记永久化

为了这道题还特地去学了标记永久化,可能对于区间修改主席树或者树套树比较有用吧OvO 我们可以把答案分为两部分:p1造成的和p2造成的 我们枚举序列,用单调栈求出序列每一个位置i,左右边第一个比它大的L,R 开三棵主席树tree1 tree2 tree3 把L扔进tree1的R位置(单点+1),L+1~i-1扔进tree2的R位置,i+1~R-1扔进tree3的L位置(区间+1) 然后询问[l,r]的时候,求出三棵区间主席树 p1造成的贡献为区间tree1内大于等于L的个数 p2造成的贡献为区间t

[HNOI2017]影魔

题目背景 影魔,奈文摩尔,据说有着一个诗人的灵魂. 事实上,他吞噬的诗人灵魂早已成千上万. 千百年来,他收集了各式各样的灵魂,包括诗人. 牧师. 帝王. 乞丐. 奴隶. 罪人,当然,还有英雄. 题目描述 每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击. 奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n.第 i个灵魂的战斗力为 k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 i, j(i<j)来说,若不存在 ks大于 k[i]或者 k

Bzoj4826 [Hnoi2017]影魔

Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 425  Solved: 244 Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样 的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己的战斗力,而影魔,靠 这些战斗力提升自己的攻击.奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n. 第 i个灵魂的战斗力

HNOI2017影魔

影魔 这么简单的方法尽然想不到,我是真的菜 对每个点,用单调栈的方式处理出他左右第一个比他大的数的位置,你可以把\(0\)和\(n+1\)设成\(inf\). 显然对于每对\(lef[i]\)和\(rig[i]\)都会做出\(p1\)的贡献 每个\(lef[i]\)会对\(i+1\)到\(rig[i]-1\)做出\(p2\)贡献 同理,每个\(rig[i]\)都会给\(lef[i]+1\)到\(i-1\)做出\(p2\)贡献 用结构体存下来,按顺序用线段树将贡献加入即可 统计贡献,对于每个询问\

bzoj 4827: [HNOI2017]礼物 (FFT)

一道FFT 然而据说暴力可以水70分 然而我省选的时候看到了直接吓傻了  连暴力都没打 太弱了啊QAQ emmmm 详细的拆开就看其他题解吧233 最后那一步卷积其实我一直没明白 后来画画图终于懂了 只要把其中一个反过来 多项式乘法的结果中的每一项系数就对应某一个Σx[i] * y[j] 的结果 前面几项是不完全的结果 但是太小了就被忽略啦 代码如下 /************************************************************** Problem:

[BZOJ 4827][Hnoi2017]礼物(FFT)

Description 我的室友最近喜欢上了一个可爱的小女生.马上就要到她的生日了,他决定买一对情侣手 环,一个留给自己,一 个送给她.每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度.但是在她生日的前一天,我的室友突 然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有 装饰物的亮度增加一个相同的自然数 c(即非负整数).并且由于这个手环是一个圆,可以以任意的角度旋转它, 但是由于上面 装饰物的方向是固定的,所以手环不能翻转.需要在经过

BZOJ 4827 [Hnoi2017]礼物 ——FFT

题目上要求一个循环卷积的最小值,直接破环成链然后FFT就可以了. 然后考虑计算的式子,可以分成两个部分分开计算. 前半部分FFT,后半部分扫一遍. #include <map> #include <ctime> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <alg