[HNOI2017]影魔

题目背景

影魔,奈文摩尔,据说有着一个诗人的灵魂。 事实上,他吞噬的诗人灵魂早已成千上万。

千百年来,他收集了各式各样的灵魂,包括诗人、 牧师、 帝王、 乞丐、 奴隶、 罪人,当然,还有英雄。

题目描述

每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。

奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n。第 i个灵魂的战斗力为 k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 i, j(i<j)来说,若不存在 ks大于 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]。

输入输出格式

输入格式:

输入文件名为 sf.in。

第一行 n,m,p1,p2

第二行 n 个数: k[1],k[2],…,k[n]

接下来 m 行, 每行两个数 a,b, 表示询问区间[a,b]中的灵魂对会为影魔提供多少攻击力。

输出格式:

输出文件名为 sf.out

共输出 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

输出样例#1:

30
39
4
13
16

说明

30%: 1<= n,m <= 500。

另 30%: p1=2*p2。

100%:1 <= n,m <= 200000; 1 <= p1,p2 <= 1000。

pre.cjk { font-family: "Droid Sans Fallback" }
p { margin-bottom: 0.25cm; line-height: 120% }

感觉这道题算不上数据结构题,这是一道思维题…
要统计每个点作为左端点和右端点的贡献,先考虑左端点.
求出每个点向右的第一个比他大的位置,记为R[i],这个可以用一个单调栈来求.
然后从右往左扫描每个点.
假设现在扫到了点i,那么右端点在R[i]以后的显然是没有贡献的(可能会有贡献,比如后面有一个点比R[i]大,但是这个区间的贡献会后面在枚举右端点的时候算到,这里不重复算.)
那么右端点在[i+1,R[i]]这个区间内的点是可能有贡献的,就先假如都有p2的贡献,那么把这个区间加上p2.
考虑到有些点并没有p2的贡献,那么他就会有p1的贡献.这时我们知道R[i]这个点会有p1的贡献,但是他被当做p2统计了两次,那么就在R[i]上+p1-2*p2.其他有p1贡献的点,也会被算到.
然后把i的贡献算完之后,计算左端点为i的询问:[1,询问右端点]的和.
这个很难想到啊,但是第二档部分分好像就是对这个的提示...考试的时候还一直不晓得这是什么套路…
然后右端点的贡献就把序列和询问区间都翻转一下然后做相同的事情就可以了.
 1 #include<bits/stdc++.h>
 2 #define ls o*2
 3 #define rs o*2+1
 4 #define mi int mid=(l+r)>>1
 5 #define maxn 200010
 6 #define LL long long
 7 using namespace std;
 8 struct data{int l,r,id;}q[maxn];
 9 int n,m,p1,p2,a[maxn];
10 LL b[maxn*4],size[maxn*4],lazy[maxn*4],ans[maxn];
11 int R[maxn];
12 inline bool cmp(const data &A,const data &B){
13   return A.l<B.l;
14 }
15 inline void down(int o){
16   if(!lazy[o]) return;
17   int k=lazy[o];lazy[o]=0;
18   lazy[ls]+=k,lazy[rs]+=k;
19   b[ls]+=k*size[ls],b[rs]+=k*size[rs];
20 }
21 void build(int o,int l,int r){
22   lazy[o]=0;
23   if(l==r){b[o]=0,size[o]=1;return;}
24   mi;
25   build(ls,l,mid),build(rs,mid+1,r);
26   b[o]=b[ls]+b[rs];
27   size[o]=size[ls]+size[rs];
28 }
29 void add(int o,int l,int r,int u,int v,int w){
30   if(l!=r) down(o);
31   if(l>=u && r<=v){b[o]+=size[o]*w;lazy[o]+=w;return;}
32   if(l>v || r<u)return;
33   mi;
34   if(v<=mid) add(ls,l,mid,u,v,w);
35   else if(u>mid) add(rs,mid+1,r,u,v,w);
36   else add(ls,l,mid,u,mid,w),add(rs,mid+1,r,mid+1,v,w);
37   b[o]=b[ls]+b[rs];
38 }
39 LL query(int o,int l,int r,int u,int v){
40   if(l!=r) down(o);
41   if(l>=u && r<=v) return b[o];
42   if(l>v || r<u)return 0;
43   mi;
44   if(v<=mid) return query(ls,l,mid,u,v);
45   else if(u>mid) return query(rs,mid+1,r,u,v);
46   else return query(ls,l,mid,u,mid)+query(rs,mid+1,r,mid+1,v);
47 }
48 inline void calc(){
49   build(1,1,n+1);
50   sort(q+1,q+m+1,cmp);a[n+1]=n+1;
51   stack<int>s;
52   s.push(1);
53   for(int i=2;i<=n+1;i++){
54     while(!s.empty() && a[i]>a[s.top()]) R[s.top()]=i,s.pop();
55     s.push(i);
56   }
57   int j=m;
58   for(int i=n;i;i--){
59     add(1,1,n+1,i+1,R[i],p2),add(1,1,n+1,R[i],R[i],p1-2*p2);
60     while(j && q[j].l==i) ans[q[j].id]+=query(1,1,n+1,1,q[j].r),j--;
61   }
62 }
63 int main(){
64   freopen("!.in","r",stdin);
65   freopen("!.out","w",stdout);
66   scanf("%d%d%d%d",&n,&m,&p1,&p2);
67   for(int i=1;i<=n;i++)
68     scanf("%d",&a[i]);
69   for(int i=1;i<=m;i++)
70     scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
71   calc();
72   reverse(a+1,a+n+1);
73   for(int i=1;i<=m;i++) q[i].l=n+1-q[i].l,q[i].r=n+1-q[i].r,swap(q[i].l,q[i].r);
74   calc();
75   for(int i=1;i<=m;i++)
76     printf("%lld\n",ans[i]);
77   return 0;
78 }
时间: 2024-10-24 14:26:05

[HNOI2017]影魔的相关文章

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

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

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\)贡献 用结构体存下来,按顺序用线段树将贡献加入即可 统计贡献,对于每个询问\

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

BZOJ4826 [Hnoi2017]影魔 【线段树 + 单调栈】

题目链接 BZOJ4826 题解 蒟蒻智力水平捉急orz 我们会发现相邻的\(i\)和\(j\)贡献一定是\(p1\),可以很快算出来[然而我一开始忘了考虑调了半天] 我们现在只考虑不相邻的 我们只需要找出所有产生贡献的\(i,j\)即可 我们发现每一个产生贡献的\(i,j\)都能对应到一个三元组\((i,k,j)\),分别对应区间的最大值,次大值,第三大值 我们枚举中间位置\(i\),找到\(i\)左边第一个比\(i\)大的位置\(L[i]\),右边第一个比\(i\)大的位置\(R[i]\)

Hnoi2017试题泛做

Day1 4825: [Hnoi2017]单旋 注意到二叉查找树的一个性质:其中序遍历就是所有元素按权值排序的顺序. 所以我们可以离线地把这棵树的中序遍历求出来.然后我们在插入的时候就可以用一个set来维护前驱后继,这样就可以维护出整棵树的形态. 接着我们发现将最大.最小单旋到根后,一定会有一边儿子是空的,并且剩下的子树的深度+1.于是我们就只要支持单点修改.区间加.单点查询的数据结构即可.树状数组就好了. 然后树的形态维护的时候大力判断一下就好啦. 1 #include <cstdio> 2

HNOI2017 day1 T2 影魔

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

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)\

HNOI2017游记

HNOI 2017 游记 DAY 0 省选即将来临,上午写了一道noip2015运输计划,复习了下LCA,中午与QYP写数列操作,他用分块写,我用线段树写,我码了七十多行代码,他有四十多行代码,我比他先打完,哈哈哈. 下午有点浪费时间,不知道干甚么,之后与高二学长们一起在楼顶开了一个振奋人心的会,我们教练与高二竞赛一班班主任做了精彩的演讲,还有学长们的经验分享.然后晚自习练习了.emcas文件配置,与欧拉函数,线性筛,希望明天万一考到打个暴力也好.就这样,回去早早睡了(也到了11点). Day