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-T_0)*z_i+s_i
\]

其中,\(T_0,z_i,s_i\)分别表示,搬来的时间,每天盈利,初始盈利;

等价于

\[T*z_i+s_i-T_0*z_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的更多相关文章

  1. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  2. [SinGuLaRiTy] COCI 2011~2012 #2

    [SinGuLaRiTy-1008] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 测试题目 对于所有的题目:Time Limit:1s   ...

  3. Windows server 2012 添加中文语言包(英文转为中文)(离线)

    Windows server 2012 添加中文语言包(英文转为中文)(离线) 相关资料: 公司环境:亚马孙aws虚拟机 英文版Windows2012 中文SQL Server2012安装包,需要安装 ...

  4. Windows Server 2012 NIC Teaming介绍及注意事项

    Windows Server 2012 NIC Teaming介绍及注意事项 转载自:http://www.it165.net/os/html/201303/4799.html Windows Ser ...

  5. 1.初始Windows Server 2012 R2 Hyper-V + 系统安装详细

    干啥的?现在企业服务器都是分开的,比如图片服务器,数据库服务器,redis服务器等等,或多或少一个网站都会用到多个服务器,而服务器的成本很高,要是动不动采购几十台,公司绝对吃不消的,于是虚拟化技术出来 ...

  6. 0.Win8.1,Win10,Windows Server 2012 安装 Net Framework 3.5

    后期会在博客首发更新:http://dnt.dkill.net 网站部署之~Windows Server | 本地部署:http://www.cnblogs.com/dunitian/p/482280 ...

  7. windows 2012 r2 can't find kb2919355

    问题   解决: 1.手动安装了 Windows8.1-KB2919442-x64 2.手动下载 KB2919355 更新成功     Turns out to have been a result ...

  8. Windows Server 2012 磁盘管理之 简单卷、跨区卷、带区卷、镜像卷和RAID-5卷

    今天给客户配置故障转移群集,在Windows Server 2012 R2的系统上,通过iSCSI连接上DELL的SAN存储后,在磁盘管理里面发现可以新建 简单卷.跨区卷.带区卷.镜像卷.RAID-5 ...

  9. VMware下Windows Server 2012添加新磁盘

    系统管理员在VM下新装了一台Windows Server 2012服务器,我在上面安装了SQL Server 2014 Standard版数据库,安装之初,只分配了一个C盘,我想在这台服务器上添加了三 ...

随机推荐

  1. Linux系统中文件行末尾出现^M的原因及解决办法

    不同系统,有不同的换行符号: 在windows下的文本文件的每一行结尾,都有一个回车('\n')和换行('\r') 在linux下的文本文件的每一行结尾,只有一个回车('\n'); 在Mac下的文本文 ...

  2. Redis系列(二):Redis高可用集群

    一.集群模式 Redis集群是一个由多个主从节点组成的高可用集群,它具有复制.高可用和分片等特性 二.集群部署 1.环境 3台主机分别是: 192.168.160.146 192.168.160.15 ...

  3. 网站优化之使用Free marker静态化网站文章页

    博客做出来的时候就想要把一些栏目和文章页都静态化处理,当时没啥时间搞,就一直没去弄.但是最近的工作就是做网站,用cms快速搭出了几个网站,cms搭建网站是真的方便啊 如果没有需要二次开发实现的功能,那 ...

  4. 从零开始手写 spring ioc 框架,深入学习 spring 源码

    IoC Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理. 创作目的 使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过 ...

  5. python数据分析三个重要方法之:numpy和pandas

    关于数据分析的组件之一:numpy ndarray的属性     4个必记参数:ndim:维度shape:形状(各维度的长度)size:总长度dtype:元素类型   一:np.array()产生n维 ...

  6. Django杂录

    Django杂录 因为是概括性的讲解,每一个方面没有具体到点,所以这篇是杂录 HHTP协议 超文本传输协议 四大特性 基于TCP/IP之上作用于应用层 基于socket请求响应 无状态 无连接 数据格 ...

  7. 管道符和作业控制、shell变量、环境变量配置文件 使用介绍

    第6周第1次课(4月23日) 课程内容: 8.6 管道符和作业控制 8.7/8.8 shell变量8.9 环境变量配置文件扩展bashrc和bash_profile的区别 http://ask.ape ...

  8. python1:基础数据类型(上)

    https://www.geekdigging.com/2019/10/13/2870915864/ 1.数字 在python的数字有4钟数据类型,分别是: int(有符号整型) long(长整型) ...

  9. python中68个内置函数的总结

    内置函数 内置函数就是python给你提供的, 拿来直接用的函数, 比如print., input等. 截止到python版本3.6.2 python一共提供了68个内置函数. #68个内置函数 # ...

  10. 华为云&#183;寻找黑马程序员#海量数据的分页怎么破?【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...