[IOI2018] meetings 会议
https://www.luogu.org/problemnew/show/P5044
题解
这种关于最大值或者最小值的问题,可以往笛卡尔树的方面想。
先考虑一个朴素的\(dp\),设\(dp[l][r]\)表示\(l\sim r\)的答案,转移是:
\]
\]
这个东西乍一看好像没什么优化空间,但是由于我们有笛卡尔树,所以我们可以加一些限制。
比如说我们强制让询问区间的一个端点为笛卡尔树上的某个端点。
然后考虑这时的转移:
\]
我们观察到随着\(i\)的向右移动,前面的部分每次都会增加\(a[p]\),后面的的部分每次增加都不会超过\(a[p]\)(根据笛卡尔树的性质)。
于是我们可以发现准备更新的这段区间被分为两部分,一部分是区间加等差数列,一部分是加常数,这个可以用线段树上二分完成。
对于一般的区间,我们直接可以把它拆成两种情况:选在最大值左边或者选在最大值右边,这样端点就有保障了,最后我们把两种情况的答案取个\(min\)就可以了。
Warning
打标记的时候要注意,因为下放的时候标记会清空,所以区间的值直接累加,不要直接更新。
代码
#include<bits/stdc++.h>
#define ls cnt<<1
#define rs cnt<<1|1
#define N 750009
using namespace std;
typedef long long ll;
ll h[N],ans[N],ans1[N],ans2[N];
int n,lo[N],p[23][N],ch[N][2],Q,rot;
vector<int>vec1[N],id1[N],vec2[N],id2[N];
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
inline int _max(int a,int b){return h[a]<h[b]?b:a;}
inline int f(int x){return n-x+1;}
inline int RMQ(int l,int r){
int loo=lo[r-l+1];
return _max(p[loo][l],p[loo][r-(1<<loo)+1]);
}
struct node{
ll val1,val2,k,b;
int tag;
}tr[N<<2];
inline void cover(int cnt,int l,int r,ll k,ll b){
tr[cnt].k=k;tr[cnt].b=b;
tr[cnt].val1=k*l+b;tr[cnt].val2=k*r+b;
tr[cnt].tag=1;
}
inline void add(int cnt,int l,int r,ll k,ll b){
tr[cnt].k+=k;tr[cnt].b+=b;
tr[cnt].val1+=k*l+b;
tr[cnt].val2+=k*r+b;//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if(!tr[cnt].tag)tr[cnt].tag=2;
}
inline void pushdown(int cnt,int l,int r){
int mid=(l+r)>>1;
if(tr[cnt].tag){
if(tr[cnt].tag==1)cover(ls,l,mid,tr[cnt].k,tr[cnt].b),cover(rs,mid+1,r,tr[cnt].k,tr[cnt].b);
else add(ls,l,mid,tr[cnt].k,tr[cnt].b),add(rs,mid+1,r,tr[cnt].k,tr[cnt].b);
tr[cnt].k=tr[cnt].b=tr[cnt].tag=0;
}
}
inline void build(int &cnt,int l,int r){
if(l>r){cnt=0;return;}
cnt=RMQ(l,r);
build(ch[cnt][0],l,cnt-1);
build(ch[cnt][1],cnt+1,r);
}
ll query(int cnt,int l,int r,int x){
if(l==r)return tr[cnt].val1;
int mid=(l+r)>>1;
pushdown(cnt,l,r);
if(mid>=x)return query(ls,l,mid,x);
else return query(rs,mid+1,r,x);
}
void clear(int cnt,int l,int r){
tr[cnt].k=tr[cnt].val1=tr[cnt].val2=tr[cnt].b=tr[cnt].tag=0;
if(l==r)return;
int mid=(l+r)>>1;
clear(ls,l,mid);clear(rs,mid+1,r);
}
void upd(int cnt,int l,int r,int x,ll y){
if(l==r){
add(cnt,l,r,0,y);
return;
}
pushdown(cnt,l,r);
int mid=(l+r)>>1;
if(mid>=x)upd(ls,l,mid,x,y);
else upd(rs,mid+1,r,x,y);
tr[cnt].val1=tr[ls].val1;tr[cnt].val2=tr[rs].val2;
}
void work(int cnt,int l,int r,int L,int R,ll k1,ll b1,ll b2){
if(l>=L&&r<=R){
if(k1*l+b1>=tr[cnt].val1+b2){
// cout<<l<<" "<<r<<" "<<tr[cnt].val1<<endl;
add(cnt,l,r,0,b2);
return;
}
if(k1*r+b1<=tr[cnt].val2+b2){
cover(cnt,l,r,k1,b1);
return;
}
}
int mid=(l+r)>>1;
pushdown(cnt,l,r);
if(mid>=L)work(ls,l,mid,L,R,k1,b1,b2);
if(mid<R)work(rs,mid+1,r,L,R,k1,b1,b2);
tr[cnt].val1=tr[ls].val1;tr[cnt].val2=tr[rs].val2;
}
void solve(int now,int l,int r,int tag){
ll num=h[now];
if(ch[now][0])solve(ch[now][0],l,now-1,0),num+=query(1,1,n,now-1);
if(ch[now][1])solve(ch[now][1],now+1,r,1);
upd(1,1,n,now,num);
if(now!=r){
ll k1=h[now],b1=num-h[now]*now,b2=h[now]*(now-l+1);
work(1,1,n,now+1,r,k1,b1,b2);
}
if(tag){
for(int i=0;i<vec1[l].size();++i){
int x=vec1[l][i],idd=id1[l][i];
ans[idd]=query(1,1,n,x);
}
}
}
int main(){
n=rd();Q=rd();
for(int i=1;i<=n;++i)h[i]=rd(),p[0][i]=i;
for(int i=1;(1<<i)<=n;++i)
for(int j=1;j+(1<<i)-1<=n;++j)p[i][j]=_max(p[i-1][j],p[i-1][j+(1<<i-1)]);
for(int i=2;i<=n;++i)lo[i]=lo[i>>1]+1;
for(int i=1;i<=Q;++i){
int l=rd()+1,r=rd()+1;
int mid=RMQ(l,r);
ans1[i]=1ll*(mid-l+1)*h[mid];
if(mid+1<=r)vec1[mid+1].push_back(r),id1[mid+1].push_back(i);
ans2[i]=1ll*(r-mid+1)*h[mid];
if(l<=mid-1)vec2[f(mid-1)].push_back(f(l)),id2[f(mid-1)].push_back(i);
}
build(rot,1,n);
solve(rot,1,n,1);
for(int i=1;i<=Q;++i)ans1[i]+=ans[i],ans[i]=0;
clear(1,1,n);
reverse(h+1,h+n+1);
for(int i=1;(1<<i)<=n;++i)
for(int j=1;j+(1<<i)-1<=n;++j)p[i][j]=_max(p[i-1][j],p[i-1][j+(1<<i-1)]);
for(int i=1;i<=n;++i){
vec1[i]=vec2[i],id1[i]=id2[i];
ch[i][0]=ch[i][1]=0;
}
build(rot,1,n);
solve(rot,1,n,1);
for(int i=1;i<=Q;++i)ans2[i]+=ans[i];
for(int i=1;i<=Q;++i)
printf("%lld\n",min(ans1[i],ans2[i]));
return 0;
}
[IOI2018] meetings 会议的更多相关文章
- 洛谷 P5044 - [IOI2018] meetings 会议(笛卡尔树+DP+线段树)
洛谷题面传送门 一道笛卡尔树的 hot tea. 首先我们考虑一个非常 naive 的区间 DP:\(dp_{l,r}\) 表示区间 \([l,r]\) 的答案,那么我们考虑求出 \([l,r]\) ...
- UOJ#410. 【IOI2018】会议
传送门 首先可以设 \(f[l][r]\) 表示 \([l,r]\) 的答案 设 \(x\) 为区间 \([l,r]\) 的最大值的位置,那么 \(f[l][r] = min(f[l][x-1]+h[ ...
- [IOI2018]会议——分治+线段树
题目链接: [IOI2018]meetings 题目大意:有$n$座山峰,每座山峰有一个高度,有$q$次询问,每次需要确定一个开会山峰使$[l,r]$所有山峰上的人都前往开会山峰,一个山峰的人去开会的 ...
- WC2019 题目集
最近写的一些 WC2019 上讲的一些题.还是怕忘了,写点东西记录一下. LOJ2983 「WC2019」数树 题意 本题包含三个问题: 问题 0:已知两棵 \(n\) 个节点的树的形态(两棵树的节点 ...
- github帐户和仓库的创建
sign up is registration and sign in is logging in for "in" is to enter an existing account ...
- 中国计算机学会CCF推荐国际学术会议
中国计算机学会推荐国际学术会议 (计算机系统与高性能计算) 一.A类 序号 会议简称 会议全称 出版社 网址 1 ASPLOS Architectural Support for Programmin ...
- CCF推荐国际学术会议
类别如下计算机系统与高性能计算,计算机网络,网络与信息安全,软件工程,系统软件与程序设计语言,数据库.数据挖掘与内容检索,计算机科学理论,计算机图形学与多媒体,人工智能与模式识别,人机交互与普适计算, ...
- 中国计算机学会CCF推荐国际学术期刊会议(最新版)
中国计算机学会推荐国际学术期刊会议 2014年12月,中国计算机学会(CCF)启动新一轮<)计算机体系结构/高性能计算/存储系统: )计算机网络:)网络与信息安全:)软件工程/系统软件/程序设计 ...
- 401 WebEx会议教程一 —— 参加会议
· WebEx会议教程一 —— 参加会议 参加他人发起的会议 1. 在邀请邮件中,接受对方的会议邀请: 2. 一般在WebEx会议开始前15分钟时,邮箱客户端会提醒您 (如下图类似提示) 3. ...
随机推荐
- list数据的存储
1 存储成csv格式 简单方法: a = [3,3,4,4] df = {'a': a} df = pd.DataFrame(df) df.to_csv('./a.csv') 复杂方法: import ...
- 应用安全-Web安全-SSRF攻防
原理 服务器: IP:.XX.191.14 nc -l -p 客户端: http://xx.map.xx.com/maps/services/thumbnails?width=215&heig ...
- 应用安全-Web安全-XSS(跨站攻击)攻防整理
分类 反射型 存储型 DOM型 XSF(Flash XSS) PDFXSS MHTML协议跨站(MHTML,data) 字符编码(UTF-7 XSS) 富文本编辑器测试 - 输入框 <img S ...
- vue组件通信之父子组件通信
准备工作: 首先,新建一个项目,如果这里有不会的同学,可以参考我转载过的文章 http://www.cnblogs.com/Sky-Ice/p/8875958.html vue 脚手架安装及新建项目 ...
- SET ANSI_NULLS ON SET QUOTED_IDENTIFIER ON 什么意思 sql server 2005 2008
原文:http://www.cnblogs.com/ForFreeDom/archive/2009/10/16/1584680.html 在sqlserver2005或SQL2008数据库项目中,创建 ...
- Lowest Common Ancestor of a Binary Tree(二叉树公共祖先)
来源:https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree Given a binary tree, find t ...
- 用jmeter监控服务器资源
jmeter可以监控服务器CPU.内存等性能参数,只需要安装一些插件,比其他方法更简单 1.下载需要的jmeter插件 如图上面两个是jmeter插件,可以再下面的链接中下载: https://jm ...
- [Web 前端] 016 css 元素的转换
三种元素之间的转换 display 属性是用来设置元素的类型及隐藏的 常用的属性有 none 元素隐藏且不占位置 block 元素以块元素显示 inline 元素以内联元素显示 inline-bloc ...
- js的事件流理解
面试问到js的事件流,当时说的不是很清楚,现在觉得有必要把这个弄清楚. 事件捕获和事件冒泡 事件流描述的是从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序. 事件流主要分为两种,即事件捕获和事 ...
- CentOS7搭建Storm集群及基础操作
前提 安装Kafka前需要先安装zookeeper集群,集体安装方法请参照我的另一篇文档 Storm安装 下载 wget https://mirrors.tuna.tsinghua.edu.cn/ap ...