[hdu7062]A Simple Problem
称序列$\{a_{1},a_{2},...,a_{n}\}$的答案为$\min_{0\le i\le n-k}(\max_{i<j\le i+k}a_{j})$(特别的,若$n<k$则为$\infty$)
将序列按$k$分段,每一段长度为$k$(最后一段长度可以小于$k$),那么恰有$\lceil\frac{n}{k}\rceil$段
考虑维护第$i$段和第$i+1$段拼接成的序列的答案,那么如果相邻两段都全在修改或查询区间内,直接再维护一棵线段树即可(支持区间加和区间取$\min$),并对剩下$o(1)$个暴力计算即可(单点修改)
关于如何"暴力计算",做法如下:
问题即选择第$i$段的一个后缀和第$i+1$段的一个前缀(都可以为空),长度和为$k$并最小化两者的最大值
(另外,如果是查询,还会对其长度有一定限制,但并不影响下面的做法)
显然两者随长度的增长单调不下降,因此即需要找到最短的后缀使得其对应的前缀(长度和为$k$)最大值小于后缀最大值(类似地找到最短的后缀),那么答案即这两个位置
简单的做法即二分+线段树做到$o(\log^{2}n)$,但注意到可以对每一段都建一棵线段树,且让两者形态相同(将最后一段长度补至$k$),那么就可以在两棵线段树上一起二分,时间复杂度降为$o(\log n)$
最终,总复杂度为$o(q\log n)$,可以通过

1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 3000005
4 #define oo 0x3f3f3f3f
5 #define mid (l+r>>1)
6 int t,n,m,q,p,l,r,x;
7 namespace VAL{
8 int V,Rt,ls[N],rs[N],tag[N],f[N];
9 unordered_map<int,int>rt;
10 void init(){
11 V=Rt=0;
12 rt.clear();
13 }
14 int New(){
15 int k=++V;
16 ls[k]=rs[k]=tag[k]=f[k]=0;
17 return k;
18 }
19 void upd(int &k,int x){
20 if (!k)k=New();
21 tag[k]+=x,f[k]+=x;
22 }
23 void up(int k){
24 f[k]=max(f[ls[k]],f[rs[k]])+tag[k];
25 }
26 void down(int k){
27 if (!tag[k])return;
28 upd(ls[k],tag[k]);
29 upd(rs[k],tag[k]);
30 tag[k]=0;
31 }
32 void update(int &k,int l,int r,int x,int y,int z){
33 if ((l>y)||(x>r))return;
34 if (!k)k=New();
35 if ((x<=l)&&(r<=y)){
36 upd(k,z);
37 return;
38 }
39 update(ls[k],l,mid,x,y,z);
40 update(rs[k],mid+1,r,x,y,z);
41 up(k);
42 }
43 void get_tag(int k,int l,int r,int x){
44 if (!k)return;
45 if (l==r){
46 upd(rt[x],tag[k]),tag[k]=0;
47 return;
48 }
49 down(k);
50 if (x<=mid)get_tag(ls[k],l,mid,x);
51 else get_tag(rs[k],mid+1,r,x);
52 up(k);
53 }
54 int query(int k,int l,int r,int x,int y){
55 if ((l>y)||(x>r))return -oo;
56 if ((!k)||(x<=l)&&(r<=y))return f[k];
57 return max(query(ls[k],l,mid,x,y),query(rs[k],mid+1,r,x,y))+tag[k];
58 }
59 int find(int k1,int k2,int l,int r,int x,int y){
60 if (l==r)return l;
61 down(k1),down(k2);
62 int xx=max(x,f[rs[k1]]),yy=max(y,f[ls[k2]]);
63 if (xx>=yy)return find(rs[k1],rs[k2],mid+1,r,x,yy);
64 return find(ls[k1],ls[k2],l,mid,xx,y);
65 }
66 void update(int pos,int l,int r,int x){
67 if (l<=r){
68 if (!pos)update(Rt,1,n/m,l,r,x);
69 else update(rt[pos],1,m,l,r,x);
70 }
71 }
72 int query(int pos,int l,int r){
73 if (l>r)return oo;
74 get_tag(Rt,1,n/m,pos),get_tag(Rt,1,n/m,pos+1);
75 l=min(max(find(rt[pos],rt[pos+1],1,m,-oo,-oo),l),r);
76 int ans=max(query(rt[pos],1,m,l,m),query(rt[pos+1],1,m,1,l-1));
77 if (l<r)ans=min(ans,max(query(rt[pos],1,m,l+1,m),query(rt[pos+1],1,m,1,l)));
78 return ans;
79 }
80 };
81 namespace ANS{
82 int V,rt,ls[N],rs[N],tag[N],f[N];
83 void init(){
84 V=rt=0;
85 }
86 int New(){
87 int k=++V;
88 ls[k]=rs[k]=tag[k]=f[k]=0;
89 return k;
90 }
91 void upd(int &k,int x){
92 if (!k)k=New();
93 tag[k]+=x,f[k]+=x;
94 }
95 void up(int k){
96 f[k]=min(f[ls[k]],f[rs[k]])+tag[k];
97 }
98 void down(int k){
99 if (!tag[k])return;
100 upd(ls[k],tag[k]);
101 upd(rs[k],tag[k]);
102 tag[k]=0;
103 }
104 void update(int &k,int l,int r,int x,int y){
105 if (!k)k=New();
106 if (l==r){
107 tag[k]=0,f[k]=y;
108 return;
109 }
110 down(k);
111 if (x<=mid)update(ls[k],l,mid,x,y);
112 else update(rs[k],mid+1,r,x,y);
113 up(k);
114 }
115 void update(int &k,int l,int r,int x,int y,int z){
116 if ((l>y)||(x>r))return;
117 if (!k)k=New();
118 if ((x<=l)&&(r<=y)){
119 upd(k,z);
120 return;
121 }
122 update(ls[k],l,mid,x,y,z);
123 update(rs[k],mid+1,r,x,y,z);
124 up(k);
125 }
126 int query(int k,int l,int r,int x,int y){
127 if ((l>y)||(x>r))return oo;
128 if ((!k)||(x<=l)&&(r<=y))return f[k];
129 return min(query(ls[k],l,mid,x,y),query(rs[k],mid+1,r,x,y))+tag[k];
130 }
131 void update(int pos,int x){
132 update(rt,1,n/m,pos,x);
133 }
134 void update(int l,int r,int x){
135 if (l<=r)update(rt,1,n/m,l,r,x);
136 }
137 int query(int l,int r){
138 if (l>r)return oo;
139 return query(rt,1,n/m,l,r);
140 }
141 };
142 int bl(int k){
143 return (k+m-1)/m;
144 }
145 int st(int k){
146 return (k-1)*m+1;
147 }
148 int ed(int k){
149 return k*m;
150 }
151 void update(int l,int r,int x){
152 int ll=bl(l),rr=bl(r);
153 if (ll==rr)VAL::update(ll,l-st(ll)+1,r-st(ll)+1,x);
154 else{
155 VAL::update(0,ll+1,rr-1,x);
156 VAL::update(ll,l-st(ll)+1,m,x);
157 VAL::update(rr,1,r-st(rr)+1,x);
158 ANS::update(ll+1,rr-2,x);
159 }
160 if (ll>1)ANS::update(ll-1,VAL::query(ll-1,1,m));
161 if (ll<n/m)ANS::update(ll,VAL::query(ll,1,m));
162 if (ll<rr-1)ANS::update(rr-1,VAL::query(rr-1,1,m));
163 if ((ll<rr)&&(rr<n/m))ANS::update(rr,VAL::query(rr,1,m));
164 }
165 int query(int l,int r){
166 int ll=bl(l),rr=bl(r+1),ans=ANS::query(ll+1,rr-2);
167 if (ll+1==rr)return min(ans,VAL::query(ll,l-st(ll)+1,r-st(rr)+2));
168 return min(ans,min(VAL::query(ll,l-st(ll)+1,m),VAL::query(rr-1,1,r-st(rr)+2)));
169 }
170 int main(){
171 scanf("%d",&t);
172 while (t--){
173 scanf("%d%d%d",&n,&m,&q);
174 n=(n+m-1)/m*m;
175 VAL::init(),ANS::init();
176 for(int i=1;i<=q;i++){
177 scanf("%d%d%d",&p,&l,&r);
178 if (p==1){
179 scanf("%d",&x);
180 update(l,r,x);
181 }
182 if (p==2)printf("%d\n",query(l,r));
183 }
184 }
185 return 0;
186 }
[hdu7062]A Simple Problem的更多相关文章
- POJ 3468 A Simple Problem with Integers(线段树 成段增减+区间求和)
A Simple Problem with Integers [题目链接]A Simple Problem with Integers [题目类型]线段树 成段增减+区间求和 &题解: 线段树 ...
- POJ 3468 A Simple Problem with Integers(线段树/区间更新)
题目链接: 传送门 A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Description Yo ...
- poj 3468:A Simple Problem with Integers(线段树,区间修改求和)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 58269 ...
- ACM: A Simple Problem with Integers 解题报告-线段树
A Simple Problem with Integers Time Limit:5000MS Memory Limit:131072KB 64bit IO Format:%lld & %l ...
- poj3468 A Simple Problem with Integers (线段树区间最大值)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 92127 ...
- POJ3648 A Simple Problem with Integers(线段树之成段更新。入门题)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 53169 Acc ...
- BZOJ-3212 Pku3468 A Simple Problem with Integers 裸线段树区间维护查询
3212: Pku3468 A Simple Problem with Integers Time Limit: 1 Sec Memory Limit: 128 MB Submit: 1278 Sol ...
- POJ 3468 A Simple Problem with Integers(线段树区间更新区间查询)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 92632 ...
- A Simple Problem with Integers(树状数组HDU4267)
A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others) Memory Limit: 32768/32768 K (J ...
随机推荐
- 使用CEF(二)— 基于VS2019编写一个简单CEF样例
使用CEF(二)- 基于VS2019编写一个简单CEF样例 在这一节中,本人将会在Windows下使用VS2019创建一个空白的C++Windows Desktop Application项目,逐步进 ...
- C++学习 2 指针
指针:指针保存的是数据的地址: #include<iostream> using namespace std; int main() { //1.定义指针 int a = 10; //指针 ...
- mybatis-plus最新版代码生成器(Swagger3)
写项目想用mybatis-plus+swagger3,百度最新版代码生成器都是旧版的,且官网的配置过于简洁,所以手敲一份,在官网的基础上加了一堆配置,lombok,restful,mvc三层结构目录等 ...
- 初步认识HCIA,什么是计算机网络,拓扑,网络的发展,交换机,路由器,IP,光纤,带宽,广播,ARP......
HCIA ---- 华为认证初级网络工程师 云技术 --- 云存储 云计算 计算机技术 : --- 抽象语言 -- 电线号的转换 抽象语言 -- 编码 ---- 应用层 编码 --- 二进制 -- ...
- JVM详解(三)——运行时数据区
一.概述 1.介绍 类比一下:红框就好比内存的运行时数据区,在各自不同的位置放了不同的东西.而厨师就好比执行引擎. 内存是非常重要的系统资源,是硬盘和CPU的中间仓库及桥梁,承载着操作系统和应用程序的 ...
- 【UE4】GAMES101 图形学作业4:贝塞尔曲线
总览 Bézier 曲线是一种用于计算机图形学的参数曲线. 在本次作业中,你需要实现de Casteljau 算法来绘制由4 个控制点表示的Bézier 曲线(当你正确实现该算法时,你可以支持绘制由更 ...
- 【c++ Prime 学习笔记】第5章 语句
C++提供了一组控制流语句,包括条件执行语句.循环语句.跳转语句. 5.1 简单语句 空语句 ; ,最简单的语句 别漏写分号,也别多写 while(cin>>s && s! ...
- vue3.x新特性之setup函数,看完就会用了
最近有小伙伴跟我聊起setup函数,因为习惯了vue2.x的写法导致了,setup用起来觉得奇奇怪怪的,在一些api混编的情况下,代码变得更加混乱了,个人觉得在工程化思想比较强的团队中使用setup确 ...
- springboot整合rabbitmq实现生产者消息确认、死信交换器、未路由到队列的消息
在上篇文章 springboot 整合 rabbitmq 中,我们实现了springboot 和rabbitmq的简单整合,这篇文章主要是对上篇文章功能的增强,主要完成如下功能. 需求: 生产者在启 ...
- Noip模拟47 2021.8.25
期望得分:55+24+53 实际得分:0+0+3 乐死 累加变量清零了吗? 打出更高的部分分暴力删了吗? 样例解释换行你看见了吗? T1 Prime 打出55分做法没删原来的暴力,结果就轻松挂55分 ...