刷题总结——影魔(HNOI2017 BZOJ4826 线段树+扫描线)
题目:
Description
Input
Output
Sample Input
7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5
Sample Output
39
4
13
16
HINT
Source
题解:
引用下lcf2000的题解,%%%%%%%%
我们枚举最大值的位置i,找出左边第一个比ai大的位置l,右边第一个比ai大的位置r,然后我们分开考虑一下p1和p2的贡献。
首先由于ai为最大值,那么左端点不会小于l,右端点不会大于r。
容易发现只有左端点为l,右端点为r才会产生p1的贡献然后产生p2贡献的有两种:一种是左端点为l,右端点在区间(i,r)中;另一种是左端点区间(l,i)中,右端点为r。
还有一种情况需要考虑,就是左端点和右端点差为1,会产生p1的贡献。对每个询问直接计算就可以了。
所以这个问题可以抽象到二维平面上。有一些点和一些线段都有权值,每次询问某个矩形内部的权值和。
于是离线排序+扫描线+树状数组即可。
自己再说一两句吧···
这道题最先开始要想到的是每次考虑对答案贡献的时候首先要想到的是枚举中间的点···而不是两旁·····
其实这种考虑贡献对象的思路在很多地方都有用到···比如有时做与树有关的题很多时候我们考虑对答案贡献都是考虑每一条边·····希望下次遇到这种题能记住这种思想···
然后就是转二维平面····这个其实比较好想···毕竟看到了点对嘛···
想到转二维那么扫描线和线段树(我是用线段树写的··对带区间修改的树状数组不是太熟···)就是顺理成章的的事情了···
然而转二维时有个细节要注意····一个点可能没有左边第一个比自己大的位置l,或者没有右边第一个比自己大的位置r,如果仅仅是这二者中间少了一个···它也是会对答案产生贡献的···比如7 9 10中的9·····md因为这一点被样例卡着过不去23333
然后就是排序了···修改一定要排在询问前面当高度相同时··这点在cdq分治时其实经常提到·····一定要注意了
最后吐槽一句洛谷为毛要卡线段树啊艹···现在哪有放树状数组不放线段树的···还是bzoj不坑···
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
using namespace std;
const int N=2e5+;
struct node
{
int x,y,h,v,id;
}q[N*];
int n,m,p1,p2,stack[N],top,num[N],Le[N],Ri[N],cnt,tag[N*];
long long ans[N],tree[N*];
inline int R()
{
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar())
f=(f<<)+(f<<)+c-'';
return f;
}
inline bool cmp(node a,node b)
{
if(a.h==b.h) return a.id<b.id;
return a.h<b.h;
}
inline void add(int k,int l,int r,int v)
{
tree[k]+=(long long)(r-l+)*v;
tag[k]+=v;
}
inline void pushdown(int k,int l,int r,int mid)
{
if(tag[k])
{
add(k*,l,mid,tag[k]);
add(k*+,mid+,r,tag[k]);
tag[k]=;
}
}
inline void modify(int k,int l,int r,int x,int y,int v)
{
if(l>=x&&r<=y)
{
add(k,l,r,v);
return;
}
int mid=(l+r)/;
pushdown(k,l,r,mid);
if(x<=mid) modify(k*,l,mid,x,y,v);
if(y>mid) modify(k*+,mid+,r,x,y,v);
tree[k]=tree[k*]+tree[k*+];
}
inline long long query(int k,int l,int r,int x,int y)
{
if(l>=x&&r<=y)
return tree[k];
int mid=(l+r)/;
pushdown(k,l,r,mid);long long temp=;
if(x<=mid) temp+=query(k*,l,mid,x,y);
if(y>mid) temp+=query(k*+,mid+,r,x,y);
return temp;
}
int main()
{
//freopen("a.in","r",stdin);
n=R(),m=R(),p1=R(),p2=R();int a,b;
for(int i=;i<=n;i++) num[i]=R();
for(int i=;i<=n;i++)
{
while(top&&num[i]>num[stack[top]]) Ri[stack[top]]=i,top--;
if(top) Le[i]=stack[top];
stack[++top]=i;
}
for(int i=;i<=m;i++)
{
a=R(),b=R();ans[i]=(long long)(b-a)*p1;
q[++cnt].x=a,q[cnt].y=b,q[cnt].h=a-,q[cnt].v=-;q[cnt].id=i;
q[++cnt].x=a,q[cnt].y=b,q[cnt].h=b,q[cnt].v=;q[cnt].id=i;
}
for(int i=;i<=n;i++)
{
if(Ri[i]&&Le[i])
{
q[++cnt].x=Le[i],q[cnt].y=Le[i],q[cnt].h=Ri[i],q[cnt].v=p1;
if(Le[i]<i-) q[++cnt].x=Le[i]+,q[cnt].y=i-,q[cnt].h=Ri[i],q[cnt].v=p2;
if(Ri[i]>i+) q[++cnt].x=i+,q[cnt].y=Ri[i]-,q[cnt].h=Le[i],q[cnt].v=p2;
}
else if(Ri[i])
{
if(i>) q[++cnt].x=,q[cnt].y=i-,q[cnt].h=Ri[i],q[cnt].v=p2;
}
else if(Le[i])
{
if(i<n) q[++cnt].x=i+,q[cnt].y=n,q[cnt].h=Le[i],q[cnt].v=p2;
}
}
sort(q+,q+cnt+,cmp);
for(int i=;i<=cnt;i++)
{
if(q[i].id)
ans[q[i].id]+=(long long)q[i].v*query(,,n,q[i].x,q[i].y);
else
modify(,,n,q[i].x,q[i].y,q[i].v);
}
for(int i=;i<=m;i++)
printf("%lld\n",ans[i]);
return ;
}
刷题总结——影魔(HNOI2017 BZOJ4826 线段树+扫描线)的更多相关文章
- 刷题总结——旅馆(bzoj1593线段树)
题目: Description 奶牛们最近的旅游计划,是到苏必利尔湖畔,享受那里的湖光山色,以及明媚的阳光.作为整个旅游的策划者和负责人,贝茜选择在湖边的一家著名的旅馆住宿.这个巨大的旅馆一共有N ( ...
- 洛谷P3722 影魔 [AH2017/HNOI2017] 线段树+扫描线
正解:线段树+扫描线 解题报告: 传送门! 先理解一下这道题,大概是这样儿的: 对于一个点对,如果他们的两端是这段区间的最大值和次大值,那么他们会有p1的贡献 如果他们的两端是最大值和一个非次大值,那 ...
- 洛谷P3246 序列 [HNOI2016] 莫队/线段树+扫描线
正解:莫队/线段树+扫描线 解题报告: 传送门! 似乎是有两种方法的,,,所以分别港下好了QAQ 第一种,莫队 看到这种询问很多区间之类的就会自然而然地想到莫队趴?然后仔细思考一下,发现复杂度似乎是欧 ...
- 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)
D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...
- 【POJ-2482】Stars in your window 线段树 + 扫描线
Stars in Your Window Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11706 Accepted: ...
- BZOJ-3225 立方体覆盖 线段树+扫描线+乱搞
看数据范围像是个暴力,而且理论复杂度似乎可行,然后被卡了两个点...然后来了个乱搞的线段树+扫描线.. 3225: [Sdoi2008]立方体覆盖 Time Limit: 2 Sec Memory L ...
- hdu 5091(线段树+扫描线)
上海邀请赛的一道题目,看比赛时很多队伍水过去了,当时还想了好久却没有发现这题有什么水题的性质,原来是道成题. 最近学习了下线段树扫描线才发现确实是挺水的一道题. hdu5091 #include &l ...
- POJ-1151-Atlantis(线段树+扫描线+离散化)[矩形面积并]
题意:求矩形面积并 分析:使用线段树+扫描线...因为坐标是浮点数的,因此还需要离散化! 把矩形分成两条边,上边和下边,对横轴建树,然后从下到上扫描上去,用col表示该区间有多少个下边,sum代表该区 ...
- 2018牛客网暑假ACM多校训练赛(第四场)E Skyline 线段树 扫描线
原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round4-E.html 题目传送门 - https://www.no ...
随机推荐
- CF Gym 100187A Potion of Immortality (思路,最坏情况的最小损失)
根据兔子试药情况可以缩小范围,如果死了,不在试过的药里面,如果活着,在试过的药里. 最糟的情况: 两个原则 1.能确定魔药所在的范围的尽量大,2.死得兔子尽量多. 如果当前不知道情况的药n为k的二倍以 ...
- [Tracking] KCF + KalmanFilter目标跟踪
基于KCF和MobileNet V2以及KalmanFilter的摄像头监测系统 简介 这是一次作业.Tracking这一块落后Detection很多年了,一般认为Detection做好了,那么只要能 ...
- python之道09
整理函数相关知识点,写博客. 看代码写结果 1. def func(): for i in range(3): print(i) return 666 print(func()) # 0 1 2 66 ...
- Java获取yml里面的配置
#yml文件配置systemPath: #档案系统地址 dossier: http://127.0.0.1:8088/ //调用说明 配置文件里必须包含节点 否则项目无法启动 @Value(" ...
- c#中的里氏转换和Java中强制类型转换在多态中的应用
在c#中: 注意: 子类并没有继承父类的构造函数,而是会默认调用父类那个无参数的构造函数. 如果一个子类继承了一个父类,那么这个子类除了可以使用自己的成员外,还可以使用从父类那里继承过来的成员.但是父 ...
- java基础—异常处理
一.异常的概念 异常指的是运行期出现的错误,也就是当程序开始执行以后执行期出现的错误.出现错误时观察错误的名字和行号最为重要.
- mysql5.7.24 解压版安装步骤以及遇到的问题
1.下载 https://dev.mysql.com/downloads/mysql/ 2.解压到固定位置,如D:\MySQL\mysql-5.7.24 3.添加my.ini文件 跟bin同级 [my ...
- Maven各种常用架包配置文件,保存一份
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...
- SAP 常用业务数据表设计
表的要求表中使用的字段请尽量参照各模块的SAP字段标准使用习惯: 例:"ZXSLRZX销售组织对应的利润中心"中的销售组织应该使用VKORG.利润中心应该使用PRCTR.根据表的 ...
- Python自定义一个数组类,支持数组之间的四则运算和其他常见方法
class MyArray: '''保证输入的内容是整型.浮点型''' def ___isNumber(self, num): if not isinstance(num, (int,float)): ...