COCI 2012 Inspektor
coci 2012 inspektor
街道由左到右分布着\(N\)个办公室,编号为\(1\)到\(N\),最开始,每个办公室都是空的,一些公司将入住,并赶走办公室里面现有的公司。一人每天会路过一些连续的办公室。他会查帐,找到最富的公司。
公司入住的描述如下:
\(1\ T\ K\ Z\ S\),\(T\)表示搬来的时间,\(K\)表示入住的办公室编号,\(Z\)表示公司每天的收益,\(S\)表示原来的余额。如果办公室原来有单位,原来的将离开,公司入住当天没有收益。
对于查帐的描述:
\(2\ T\ A\ B\) , \(T\)表示查帐的时间。\(A\)和\(B\)表示要查的办公室在\(A\)和\(B\)之间(包涵端点)。查帐时要算当天的收益。
输入
第一行两个正整数 \(N (1 ≤ N ≤ 100 000) and M (1 ≤ M ≤ 300 000)\),表示办公室的间数,\(M\)表示有\(M\)个事件。
接下来\(M\)行,每行描述一个事件\(1\ T\ K\ Z\ S\) 或\(2\ T\ A\ B\)所有事件按时间顺序给出。 每天最多发生一个事件,所以\(T\)严格递增 \(T\)小于\(10^6\),\(Z\)和\(S\)的绝对值小于\(10^6\).
输出
对于每一次查帐输出一行,表示最富的公司的钱数,如果没有公司输出\(nema\).
input
2 4
1 1 1 2 4
1 2 2 3 2
2 5 1 2
2 7 1 2
output
12
17
input
3 6
1 1 1 4 -2
1 2 2 2 6
2 3 3 1
2 4 3 1
1 5 3 -6 20
2 6 2 3
output
8
10
14
input
5 9
1 1 5 4 -5
2 2 3 5
1 3 4 6 9
2 4 1 2
1 6 2 2 3
2 8 2 1
1 9 4 0 17
2 10 5 5
2 11 1 4
output
-1
nema
7
31
17
当前是第\(T\)天时,对于每一个公司,盈利是
\]
其中,\(T_0,z_i,s_i\)分别表示,搬来的时间,每天盈利,初始盈利;
等价于
\]
发现这是一个一次函数,意味着每个公司都可以用一条直线来表示;
我们可以维护每个时间点的坐标系,找到当\(x\)取\(T\)时的最大值,这就是答案;
我们先不考虑修改操作;看怎样找到\(T\)取值下的最大值;
在一个坐标系里,有可能被取成最大值只可能是最上面的直线;
比如:
只有红色部分可能是答案直线,我们也只用维护这一部分;
这其实就是一个下凸壳,我们可以用单调栈来构造,用一个指针扫描来寻找答案;
关于下凸壳的构造
我们需要按顺序维护出在下凸壳上的直线的编号,
可以发现下凸壳上的直线的斜率是单调递增的,两两直线的交点与直线对应,横坐标也是单调递增的;
我们先把直线按斜率大小排序(小的在前
我们可以按横坐标维护一个存交点的单调栈;
因为交点也是两条直线得来的,我们可以直接把直线放到栈内,相邻两条直线的交点的横坐标保证单调递增;
当我们新加入一条直线时,如果这条直线与栈顶直线的交点,在栈顶交点(就是栈顶直线与栈内的第二条直线的交点,它的横坐标是当前最大的) 右边,那么这条直线可以直接加入栈中;
如果在栈顶交点的左边,应当把栈顶交点弹出(其实就是把栈顶直线弹出,这个交点就没有了),直到当前直线与栈顶直线的交点成为最大值,再把当前直线加入栈中。(单调栈的基本操作)
最后栈内的直线,就是下凸壳中的直线;
举个例子
我先加入第一条直线,这是斜率最小的一条直线
再加入第二条直线,因为当前栈内直线只有一条,还没有交点,就直接加入
红色部分就是当前栈维护出的下凸壳;
\(A\)就是现在横坐标最大的交点
再加入第三条直线,它与第二条直线的交点在\(A\)右边,我们可以直接加入;
\(B\)就是现在横坐标最大的交点
第三条直线是栈顶直线,红色部分是下凸壳
再加入第四条直线,它与第三条直线的交点在\(B\)左边,我们发现第三条直线已不能在下凸壳里了,应先把第三条直线弹出,
再发现第四条直线与第二条直线的交点在\(A\)右边,可以加入第四条直线;
现在的\(B\)是横坐标的最大的交点
栈内元素应该是\(1,2,4\),也就是下凸壳中的直线(红色部分);
构造的时间复杂度是\(O(nlogn)\)
关于在已有下凸壳上求解
我们想知道横坐标是\(T\)时,下凸壳上的纵坐标;
主要目的就是找\(x=T\)这条直线与哪条直线相交
根据之前的操作,我们知道下凸壳中直线的分界是依据交点的;
我们先要保证交点与直线对应,
假设这个交点所对应的直线是相交的两条直线的前一条;
我们找到第一个横坐标大于等于\(T\)的交点,那么它对应的直线应该与\(x=T\)相交,也就是答案直线;
当前第一个大于等于\(T\)的交点是\(B\),可知\(x=T\)与直线\(2\)相交
又由于我们询问的\(T\)是严格单增的,那答案交点也是单增的,我们只需要记录这个凸壳已经被扫到哪里了,下次从这里开始就可以了;
查询的总时间复杂度是\(O(T)\)
考虑有修改操作的情况
修改具有不可继承性,修改后的凸壳和之前的凸壳是可能没有相同点的;
修改一条直线可能改变凸壳的全貌;
意味着每次修改一条直线,都需要重构凸壳,这样成本太高了;
我们可以考虑分块;
对\(n\)分块,假设每个块大小是\(B\),我们在每个块中维护一个这个区间的凸壳;
对于查询,不是整块的暴力扫描,是整块的用指针在对应块找答案,前者复杂度是\(O(B)\),后者总时间复杂度是\(O(\frac{n}{B}*T)\),\(T\)是最大时间;
对于修改,把待修改的块打上标记,当调用它是进行一次重构,对于一次重构时间复杂度是\(O(BlogB)\)
\(Code\)
#include<bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int N=100005;
int n,m,len,opt;
int pos[N],L[N],R[N];
struct line
{
ll k,b;//斜率和截距
bool operator<(line l)const
{
return k==l.k?b>l.b:k<l.k; //按斜率排序,斜率相同按截距
}
}a[N],b[N];
bool vis[N],use[N],need[N];
int head[N],tail[N]; //第i块在栈中的首尾
int sta[N]; //栈,存直线的下标
double point[N]; //记录交点
inline ll max(ll x,ll y){return x>y?x:y;}
inline int read()
{
int x=0,f=1;char st=getchar();
while(st<'0'||st>'9'){if(st=='-') f=-1;st=getchar();}
while(st>='0'&&st<='9') x=x*10+st-'0',st=getchar();
return x*f;
}
inline void write(ll x)
{
if(x<0) x=~x+1,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline double getx(line x,line y)
{
return (double)(x.b-y.b)/(y.k-x.k); //算两条直线交点的横坐标
}
inline void rebuild(int x)
{
int st=L[x]-1,top=L[x];
for(re int i=L[x];i<=R[x];++i)
if(vis[i]) b[++st]=a[i]; //把需要重构的直线加入
sort(b+L[x],b+st+1);
sta[top]=L[x];
for(re int i=L[x]+1;i<=st;++i)
if(b[i].k!=b[i-1].k) //如果两条直线斜率相同,只可能取到截距大的一条
{
while(top>L[x]&&getx(b[i],b[sta[top]])<getx(b[sta[top]],b[sta[top-1]])) top--;
point[top]=getx(b[i],b[sta[top]]); //算交点
sta[++top]=i;
}
head[x]=L[x];
tail[x]=top;
}
inline void doit(int t,int l,int r)
{
if(l>r) swap(l,r);
ll tmp=-1e18;
int p=pos[l],q=pos[r];
if(p==q)
{
for(re int i=l;i<=r;++i)
if(vis[i]) tmp=max(tmp,t*a[i].k+a[i].b); //暴力
}
else
{
for(re int i=l;i<=R[p];++i)
if(vis[i]) tmp=max(tmp,t*a[i].k+a[i].b);
for(re int i=L[q];i<=r;++i)
if(vis[i]) tmp=max(tmp,t*a[i].k+a[i].b);
for(re int i=p+1;i<q;++i)
{
if(need[i]) //如果需要重构
{
rebuild(i);
need[i]=0;
}
if(use[i])
{
while(head[i]<tail[i]&&point[head[i]]<t) head[i]++; //找第一个大于等于t的交点
tmp=max(tmp,t*b[sta[head[i]]].k+b[sta[head[i]]].b);
}
}
}
if(tmp==-1e18) puts("nema");
else write(tmp),puts("");
}
int main()
{
freopen("inspektor.in","r",stdin);
freopen("inspektor.out","w",stdout);
n=read();m=read();
len=sqrt(n/log2(n))+1;
// len=144;
for(re int i=1;i<=n;++i)
pos[i]=(i-1)/len+1;
for(re int i=1;i<=pos[n];++i)
L[i]=R[i-1]+1,R[i]=R[i-1]+len;
R[pos[n]]=n;
while(m--)
{
opt=read();
if(opt==1)
{
int T=read(),x=read(),z=read(),s=read();
vis[x]=1;use[pos[x]]=1;//这个点有,这个块有
need[pos[x]]=1;//需要重构
a[x].k=z;a[x].b=s-(ll)T*z;
}
else
{
int T=read(),l=read(),r=read();
doit(T,l,r);
}
}
fclose(stdin);
fclose(stdout);
return 0;
}
COCI 2012 Inspektor的更多相关文章
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- [SinGuLaRiTy] COCI 2011~2012 #2
[SinGuLaRiTy-1008] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 测试题目 对于所有的题目:Time Limit:1s ...
- Windows server 2012 添加中文语言包(英文转为中文)(离线)
Windows server 2012 添加中文语言包(英文转为中文)(离线) 相关资料: 公司环境:亚马孙aws虚拟机 英文版Windows2012 中文SQL Server2012安装包,需要安装 ...
- Windows Server 2012 NIC Teaming介绍及注意事项
Windows Server 2012 NIC Teaming介绍及注意事项 转载自:http://www.it165.net/os/html/201303/4799.html Windows Ser ...
- 1.初始Windows Server 2012 R2 Hyper-V + 系统安装详细
干啥的?现在企业服务器都是分开的,比如图片服务器,数据库服务器,redis服务器等等,或多或少一个网站都会用到多个服务器,而服务器的成本很高,要是动不动采购几十台,公司绝对吃不消的,于是虚拟化技术出来 ...
- 0.Win8.1,Win10,Windows Server 2012 安装 Net Framework 3.5
后期会在博客首发更新:http://dnt.dkill.net 网站部署之~Windows Server | 本地部署:http://www.cnblogs.com/dunitian/p/482280 ...
- windows 2012 r2 can't find kb2919355
问题 解决: 1.手动安装了 Windows8.1-KB2919442-x64 2.手动下载 KB2919355 更新成功 Turns out to have been a result ...
- Windows Server 2012 磁盘管理之 简单卷、跨区卷、带区卷、镜像卷和RAID-5卷
今天给客户配置故障转移群集,在Windows Server 2012 R2的系统上,通过iSCSI连接上DELL的SAN存储后,在磁盘管理里面发现可以新建 简单卷.跨区卷.带区卷.镜像卷.RAID-5 ...
- VMware下Windows Server 2012添加新磁盘
系统管理员在VM下新装了一台Windows Server 2012服务器,我在上面安装了SQL Server 2014 Standard版数据库,安装之初,只分配了一个C盘,我想在这台服务器上添加了三 ...
随机推荐
- this绑定方式总结
最近在回顾js的一些基础知识,把<你不知道的js>系列又看了一遍,this始终是重中之重,还是决定把this相关知识做一个系统的总结,也方便自己日后回顾. this的四条绑定规则 1.默认 ...
- pod删除主要流程源码解析
本文以v1.12版本进行分析 当一个pod删除时,client端向apiserver发送请求,apiserver将pod的deletionTimestamp打上时间.kubelet watch到该事件 ...
- 在ensp上利用三层交换机实现VLAN间路由
我们在实际生活中经常要跨vlan进行通信,我们的解决办法有单臂路由,但是单臂路由存在很大的局限性,带宽,转发效率等,所以单臂路由用的就有点少,所以就有了本章节 三层交换机在原有的二层交换机的基础上,增 ...
- linux/CentOS的安装(萌新版)
一.CentOS的下载 1.官网下载网址:https://www.centos.org/ 2.下载具体步骤(2019年9月): 1.浏览器输入官方网址 2.点击网页的橙色按钮进入到下一界面 3.此时会 ...
- 【Linux系列】Centos 7安装 Mysql8.0(五)
目的 本文主要介绍以下两点: 一. 如何安装Mysql8.0 二. Navicat连接Mysql 一. 如何安装Mysql8.0 安装Mysql有两种方式: 直接下载官方的源(比较慢) https:/ ...
- 学习PHP框架只停留在会用层面,职业生涯肯定走不远!
工作这么多年,也面试过很多PHP工程师,我发现很多PHP工程师只停留在使用框架的层面,然而对框架底层根本没有深入去了解,那么这就会给自己的职业生涯带来一定的瓶颈,当遇到问题的时候你就无从下手,不知道如 ...
- Slickflow.Graph 开源工作流引擎快速入门之四: 图形编码建模工具使用手册
前言: 业务人员绘制流程时,通常使用图形GUI界面交互操作来完成,然而对于需要频繁操作或者管理较多流程的系统管理用户,就需要一款辅助工具,来帮助他们快速完成流程的创建和编辑更新.Slickflow.G ...
- 02 jQuery中的事件、动画、复合函数
jQuery中的事件 在JavaScript中,常用的基础事件有鼠标事件.键盘事件.window事件.表单事件.事件绑定和处理函数的语法格式如下 语法q 事件名 = "函数名()" ...
- SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”
1.问题描述: 我的项目是tcServer,在运行的之后出现如下错误: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBin ...
- 原创001 | 搭上SpringBoot自动注入源码分析专车
前言 如果这是你第二次看到师长的文章,说明你在觊觎我的美色!O(∩_∩)O哈哈~ 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 本系列为SpringBoot深度源码专车系列,第一篇发车 ...