博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【bzoj4826】[Hnoi2017]影魔 单调栈+可持久化线段树
阅读量:5044 次
发布时间:2019-06-12

本文共 3759 字,大约阅读时间需要 12 分钟。

题目描述

影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。奈文摩尔有 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]。

输入

第一行 n,m,p1,p2
第二行 n 个数:k[1],k[2],...,k[n]
接下来 m 行,每行两个数 a,b,表示询问区间[a,b]中的灵魂对会为影魔提供多少攻击力。
1 <= n,m <= 200000;1 <= p1,p2 <= 1000

输出

共输出 m 行,每行一个答案,依次对应 m 个询问。

样例输入

10 5 2 3

7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5

样例输出

30

39
4
13
16


题解

单调栈+可持久化线段树

先使用单调栈求出i左边第一个比i大的位置l[i],和右边第一个比i大的位置r[i]。

考虑i对答案的贡献,当且仅当i作为区间[x+1,y-1]的最大值时,i才对点对(x,y)有贡献。

根据题意,第一种情况i产生贡献的点对是(l[i] , r[i]),

第二种情况i产生贡献的点对是(l[i] , i+1~r[i]-1)和(r[i] , l[i]+1~i-1)。

同时还要加上特殊情况(i , i+1)。

问题便转化为在二维平面上,有一些线段被涂色(点算作特殊的包含点数为1的线段),问一个矩形区域内的涂色的点的个数。

可以使用扫描线来解决,然而蒟蒻不会,所以写了主席树。

发现点对的第一个点都是固定的,所以我们可以以第一个点为根建立可持久化线段树,并在对应的可持久化线段树上进行区间更新。

然而可持久化线段树的pushdown比较复杂,所以我使用了标记永久化的方法来完成。

最后查询的矩形是(a,a)与(b,b)之间的部分,查询[a,b]内root[b]与root[a-1]的差即为答案。

#include 
#include
#define N 200010#define lson l , mid , ls[x] , ls[y]#define rson mid + 1 , r , rs[x] , rs[y]using namespace std;typedef long long ll;struct data{ int x , l , r; ll p; data() {} data(int x0 , int l0 , int r0 , ll p0) {x = x0 , l = l0 , r = r0 , p = p0;}}v[N << 2];int a[N] , lp[N] , rp[N] , sta[N] , top , cnt , root[N] , ls[N << 6] , rs[N << 6] , tot;ll sum[N << 6] , add[N << 6];bool cmp(data a , data b){ return a.x < b.x;}void pushup(int x){ sum[x] = sum[ls[x]] + sum[rs[x]];}void insert(int b , int e , ll a , int l , int r , int x , int &y){ y = ++tot , ls[y] = ls[x] , rs[y] = rs[x] , add[y] = add[x] , sum[y] = sum[x] + a * (e - b + 1); if(b == l && r == e) { add[y] += a; return; } int mid = (l + r) >> 1; if(e <= mid) insert(b , e , a , lson); else if(b > mid) insert(b , e , a , rson); else insert(b , mid , a , lson) , insert(mid + 1 , e , a , rson);}ll query(int b , int e , int l , int r , int x , int y){ if(b <= l && r <= e) return sum[y] - sum[x]; int mid = (l + r) >> 1; ll ans = (add[y] - add[x]) * (e - b + 1); if(e <= mid) return ans + query(b , e , lson); else if(b > mid) return ans + query(b , e , rson); else return ans + query(b , mid , lson) + query(mid + 1 , e , rson);}int main(){ int n , m , i , j , x , y; ll p1 , p2; scanf("%d%d%lld%lld" , &n , &m , &p1 , &p2); for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]); a[0] = a[n + 1] = 1 << 30 , top = 1; for(i = 1 ; i <= n ; i ++ ) { while(a[sta[top]] < a[i]) top -- ; lp[i] = sta[top] , sta[++top] = i; } top = 1 , sta[1] = n + 1; for(i = n ; i >= 1 ; i -- ) { while(a[sta[top]] < a[i]) top -- ; rp[i] = sta[top] , sta[++top] = i; } for(i = 1 ; i <= n ; i ++ ) { if(lp[i] != 0 && rp[i] != n + 1) v[++cnt] = data(lp[i] , rp[i] , rp[i] , p1); if(i < n) v[++cnt] = data(i , i + 1 , i + 1 , p1); if(lp[i] != 0 && rp[i] - i > 1) v[++cnt] = data(lp[i] , i + 1 , rp[i] - 1 , p2); if(rp[i] != n + 1 && i - lp[i] > 1) v[++cnt] = data(rp[i] , lp[i] + 1 , i - 1 , p2); } sort(v + 1 , v + cnt + 1 , cmp); for(i = j = 1 ; i <= n ; i ++ ) { root[i] = root[i - 1]; while(j <= cnt && v[j].x == i) insert(v[j].l , v[j].r , v[j].p , 1 , n , root[i] , root[i]) , j ++ ; } while(m -- ) { scanf("%d%d" , &x , &y); printf("%lld\n" , query(x , y , 1 , n , root[x - 1] , root[y])); } return 0;}

 

 

转载于:https://www.cnblogs.com/GXZlegend/p/7115363.html

你可能感兴趣的文章
BZOJ 2338 HNOI2011 数矩形 计算几何
查看>>
关于页面<!DOCTYPE>声明
查看>>
【AS3代码】播放FLV视频流的三步骤!
查看>>
C++标准库vector使用(更新中...)
查看>>
cocos2d-x 2.2.6 之 .xml文件数据读取
查看>>
枚举的使用
查看>>
BZOJ 1531 二进制优化多重背包
查看>>
BZOJ 2324 (有上下界的)费用流
查看>>
python3基础06(随机数的使用)
查看>>
Zookeeper系列(二)特征及应用场景
查看>>
【HTTP】Fiddler(三)- Fiddler命令行和HTTP断点调试
查看>>
Spring Boot使用Druid和监控配置
查看>>
poi 处理空单元格
查看>>
Android 内存泄漏优化总结
查看>>
luogu4849 寻找宝藏 (cdq分治+dp)
查看>>
Spring Cloud微服务笔记(五)Feign
查看>>
C语言键盘按键列表
查看>>
Codeforces Round #374 (Div. 2)
查看>>
oracle数据类型
查看>>
socket
查看>>