【HNOI 2017】影魔
Problem
Description
影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。
每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。
奈文摩尔有 \(n\) 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 \(1\) 到 \(n\)。第 \(i\) 个灵魂的战斗力为 \(k_i\),灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 \(i, j(i<j)\) 来说,若不存在 \(k_s(i<s<j)\) 大于 \(k_i\) 或者 \(k_j\),则会为影魔提供 \(p_1\) 的攻击力(可理解为:当 \(j = i + 1\) 时,因为不存在满足 \(i < s < j\) 的 \(s\),从而 \(k_s\) 不存在,这时提供 \(p_1\) 的攻击力;当 \(j > i + 1\) 时,若 \(\max\{k_s | i < s < j\}\le \min(k_i, k_j)\),则提供 \(p_1\) 的攻击力);另一种情况,令 \(c\) 为 \(k_{i + 1}, k_{i + 2}, \cdots, k_{j -1}\) 的最大值,若 \(c\) 满足:\(k_i < c < k_j\),或者 \(k_j < c < k_i\),则会为影魔提供 \(p_2\) 的攻击力,当这样的 \(c\) 不存在时,自然不会提供这 \(p_2\) 的攻击力;其他情况的点对,均不会为影魔提供攻击力。
影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任意一段区间 \([a,b]\),位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑所有满足 \(a\le i<j\le b\) 的灵魂对 \(i, j\) 提供的攻击力之和。
顺带一提,灵魂的战斗力组成一个 \(1\) 到 \(n\) 的排列:\(k_1, k_1, \cdots, k_n\)。
Input Format
第一行四个整数 \(n,m,p_1,p_2\);
第二行 \(n\) 个整数数:\(k_1, k_2,\cdots, k_n\);
接下来 \(m\) 行,每行两个数 \(a,b\),表示询问区间 \([a,b]\) 中的灵魂对会为影魔提供多少攻击力。
Output Format
共输出 \(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
Output
30
39
4
13
16
Range
对于 \(30\%\) 的数据,\(1\le n, m\le 500\);
另有 \(30\%\) 的数据,\(p_1 = 2p_2\);
对于 \(100\%\) 的数据,\(1\le n,m\le 200000, 1\le p_1, p_2\le 1000\)。
Algorithm
线段树
Mentality
蛮简单的一道题吧 \(......\)
不难想到,我们应该首先求出两个数组 \(ll[i],rr[i]\) 分别代表 \(i\) 左边第一个比 \(a[i]\) 大的数的位置和右边第一个比 \(a[i]\) 大的数的位置。
具体怎么求呢?维护一个单调递减的单调栈就好了。详见代码。
然后我们发现,对于每个区间 \([i,i+1]\) ,它们必定都有 \(p1\) 的贡献,这个其实在输入询问的时候就可以处理了,即 \(ans+=(r-l)*p1\) 。
那么不难发现对于一个位置 \(i\) ,它对区间 \([ll[i]+1\sim i-1,rr[i]]\) 和区间 \([ll[i],i+1\sim rr[i]-1]\) 都能产生 \(p2\) 的贡献,那我们只需要将每个点 \(i\) 挂载在 \(ll[i],rr[i]\) 两个位置上,一旦扫到 \(ll[i]\) ,就将 \([i+1,rr[i]]\) 这段区间都加上 \(p2\) ,扫到 \(rr[i]\) ,就将 \(ll[i]\) 位置加上 \(p1\) ,将 \([ll[i]+1,i-1]\) 这段区间都加上 \(p2\) 即可统计区间贡献。
那么如何统计答案呢?其实很简单,对于每个询问区间 \([l,r]\) ,我们只需要保证统计的值全部都来自询问区间内的点对即可。那么换句话说,我们可以用总贡献减去不属于询问区间的贡献。
即我们在扫到某个询问左端点前一个位置 \(l-1\) 时,记录下 \([l,r]\) 的贡献和 \(sum1\) ,这些就是不属于询问区间的贡献,而扫到右端点 \(r\) 时记录下贡献和 \(sum2\) ,这些就是总贡献,那么答案就是 \(sum2-sum1\) 。
很简单伐。
注意事项:
那些 \([i,i+1]\) 的小贡献要加上。
对于一个点 \(i\) ,若左边或右边没有更大的了,将贡献区间左右端点挂载 \(0\) 和 \(n+1\) 上,因为这种情况并不能产生贡献。
Code
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
#define ls (o << 1)
#define rs ((o << 1) + 1)
#define mid ((l + r) >> 1)
int n, m, p1, p2, a[200001], ql[200001], qr[200001];
int top, L, R, x, stack[200001], rr[200001], ll[200001];
long long ans, sum[800005], adv[800005], sum1[200001], sum2[200001];
vector<int> Mount[5][200005];
void pushdown(int o, int l, int r) {
adv[ls] += adv[o], adv[rs] += adv[o];
sum[ls] += 1ll * (mid - l + 1) * adv[o];
sum[rs] += 1ll * (r - mid) * adv[o];
adv[o] = 0;
}
void add(int o, int l, int r) {
if (L > R) return;
if (l >= L && r <= R) {
sum[o] += 1ll * (r - l + 1) * x, adv[o] += x;
return;
}
pushdown(o, l, r);
if (mid >= L) add(ls, l, mid);
if (mid < R) add(rs, mid + 1, r);
sum[o] = sum[ls] + sum[rs];
}
void query(int o, int l, int r) {
if (l >= L && r <= R) {
ans += sum[o];
return;
}
pushdown(o, l, r);
if (mid >= L) query(ls, l, mid);
if (mid < R) query(rs, mid + 1, r);
sum[o] = sum[ls] + sum[rs];
}
void Add(int l, int r, int w) {
L = l, R = r, x = w;
add(1, 0, n);
}
void Query(int l, int r) {
L = l, R = r, ans = 0;
query(1, 0, n);
}
int main() {
freopen("3722.in", "r", stdin);
freopen("3722.out", "w", stdout);
cin >> n >> m >> p1 >> p2;
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
stack[top = 0] = 0; //初始值设为 0 和 n+1
for (int i = 1; i <= n; i++) {
while (top > 0 && a[stack[top]] < a[i]) top--;
ll[i] = stack[top], stack[++top] = i;
} //单调栈预处理 ll,rr 数组
stack[top = 0] = n + 1;
for (int i = n; i >= 1; i--) {
while (top > 0 && a[stack[top]] < a[i]) top--;
rr[i] = stack[top], stack[++top] = i;
}
for (int i = 1; i <= n; i++) {
Mount[1][rr[i]].push_back(i);
Mount[2][ll[i]].push_back(i);
} //挂载贡献区间
int l, r;
for (int i = 1; i <= m; i++) {
scanf("%d%d", &ql[i], &qr[i]);
sum2[i] += 1ll * (qr[i] - ql[i]) * p1;
Mount[3][ql[i] - 1].push_back(i);
Mount[4][qr[i]].push_back(i);
} //挂载询问端点
for (int i = 1; i <= n; i++) {
for (int j = 0, limit = Mount[1][i].size(); j < limit; j++) {
int to = Mount[1][i][j];
Add(ll[to], ll[to], p1);
Add(ll[to] + 1, to - 1, p2);
}
for (int j = 0, limit = Mount[2][i].size(); j < limit; j++) {
int to = Mount[2][i][j];
Add(to + 1, rr[to] - 1, p2);
}
for (int j = 0, limit = Mount[3][i].size(); j < limit; j++) {
int to = Mount[3][i][j];
Query(ql[to], qr[to]);
sum1[to] = ans;
}
for (int j = 0, limit = Mount[4][i].size(); j < limit; j++) {
int to = Mount[4][i][j];
Query(ql[to], qr[to]);
sum2[to] += ans;
}
}
for (int i = 1; i <= m; i++) printf("%lld\n", sum2[i] - sum1[i]);
}
【HNOI 2017】影魔的更多相关文章
- [HNOI 2017]影魔
Description 题库链接 给你一段长度为 \(n\) 的序列 \(K\) . \(m\) 组询问,每次给定左右端点 \(l,r\) .求出满足区间内下述贡献和. 如果一个区间的两个端点是这一个 ...
- [HNOI/AHOI2017]影魔
[HNOI/AHOI2017]影魔 题目大意: 有一排\(n(n\le2\times10^5)\)个数\(k_{1\sim n}\).对于点对\((i,j)\),若不存在\(k_s(i<s< ...
- [HNOI 2017]单旋
Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据 结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的 ...
- [HNOI 2017]抛硬币
Description 题库链接 两人抛硬币一人 \(a\) 次,一人 \(b\) 次.记正面朝上多的为胜.问抛出 \(a\) 次的人胜出的方案数. \(1\le a,b\le 10^{15},b\l ...
- [HNOI 2017]礼物
Description 我的室友最近喜欢上了一个可爱的小女生.马上就要到她的生日了,他决定买一对情侣手 环,一个留给自己,一个送给她.每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度.但是在 ...
- 【HNOI 2017】大佬
Problem Description 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语.你作为一个 OIer, ...
- HNOI 2017
题目链接 我还是按bzoj AC数量排序做的 4827 这个其实如果推一下(求每个值)式子会发现是个卷积,然后FFT就好了 4826 记不太清了,可以求出每个点左右第一个比他的的点的位置,将点对看成平 ...
- 【HNOI 2017】礼物
Problem Description 我的室友最近喜欢上了一个可爱的小女生.马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她.每个手环上各有 \(n\) 个装饰物,并且每个装饰物 ...
- [HNOI 2017]大佬
Description 题库链接 题意简述来自Gypsophila. 你现在要怼 \(m\) 个大佬,第 \(i\) 个大佬的自信值是 \(C_i\) .每次怼大佬之前,你的自信值是 \(mc\),等 ...
随机推荐
- [转]理解 Bias 与 Variance 之间的权衡----------bias variance tradeoff
有监督学习中,预测误差的来源主要有两部分,分别为 bias 与 variance,模型的性能取决于 bias 与 variance 的 tradeoff ,理解 bias 与 variance 有助于 ...
- C++ 实验2
#include <iostream> using namespace std; template<class T> void insertionSort(T a[],int ...
- ajax的get和post请求 -- 基于flask 简单示例
需求:在浏览器端输入姓名,将数据发送给后端,后端将内容追加到 user.json 中,并将该文件中的数据,返回到浏览器打印 1.浏览器端(html文件) index.html文件 <!DOCTY ...
- JDK1.8 StampedLock: 解决ReentrantReadWriteLock在读多写少情况下,写线程饥饿问题
ReentrantReadWriteLock 在沒有任何读写锁时,才可以取得写入锁,这可用于实现了悲观读取(Pessimistic Reading), 即如果执行中进行读取时,经常可能有另一执行要写入 ...
- 获奖感想与Java阶段性学习总结
获奖感想 其实我早就知道有小黄衫这个东西,而且它就在我的目标清单里,不过没想到娄老师发的这么早.我想小黄衫代表着的是老师对我这一阶段来学习成果和努力的肯定,虽然Java学习中付出很多时间精力,现在也值 ...
- Hydra(爆破神器)
PS:这款暴力密码破解工具相当强大,支持几乎所有协议的在线密码破解,其密码能否被破解关键在于字典是否足够强大.对于社会工程型渗透来说,有时能够得到事半功倍的效果.本文仅从安全角度去探讨测试,使用本文内 ...
- word_freq
1) 博客开头给出自己的基本信息,格式建议如下: 学号:2017*****7193(保留前4位和后4位,中间用星号代替,避免泄露个人信息): 姓名:刘新飞,用你的真实姓名替代 我的码云仓库地址:[ht ...
- 用php实现表格
<?php $contact2 =[ ['江苏'=>['华罗庚','河南','童第周']], ['河南'=>['童第周','华罗庚','河南']], ['河北'=>['刘恒', ...
- CF830A Office Keys(贪心)
CF830A Office Keys [题目链接]CF830A Office Keys [题目类型]贪心 &题意: 有n个人,k个钥匙,一个目的地,求让n个人都回到目的地的最短时间,每个人都要 ...
- react使用create-react-app创建的项目部署
一.在所有的项目代码编写完成后,react项目直接部署是无法正常访问的 1.问题一 网页无法正常的浏览器刷新,刷新会报404错,路由找不到页面 2.问题二 路由跳转后,浏览器后退按钮点击后,页面不刷新 ...