称序列$\{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的更多相关文章

  1. POJ 3468 A Simple Problem with Integers(线段树 成段增减+区间求和)

    A Simple Problem with Integers [题目链接]A Simple Problem with Integers [题目类型]线段树 成段增减+区间求和 &题解: 线段树 ...

  2. POJ 3468 A Simple Problem with Integers(线段树/区间更新)

    题目链接: 传送门 A Simple Problem with Integers Time Limit: 5000MS     Memory Limit: 131072K Description Yo ...

  3. poj 3468:A Simple Problem with Integers(线段树,区间修改求和)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 58269   ...

  4. ACM: A Simple Problem with Integers 解题报告-线段树

    A Simple Problem with Integers Time Limit:5000MS Memory Limit:131072KB 64bit IO Format:%lld & %l ...

  5. poj3468 A Simple Problem with Integers (线段树区间最大值)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 92127   ...

  6. POJ3648 A Simple Problem with Integers(线段树之成段更新。入门题)

    A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 53169 Acc ...

  7. 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 ...

  8. POJ 3468 A Simple Problem with Integers(线段树区间更新区间查询)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 92632   ...

  9. A Simple Problem with Integers(树状数组HDU4267)

    A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others) Memory Limit: 32768/32768 K (J ...

随机推荐

  1. C++核心编程 3 函数提高

    函数默认参数 在C++中,函数的形参列表中的形参是可以有默认值的: 语法:返回值类型 函数名 (参数 = 默认值){ } 实例: #include<iostream> using name ...

  2. LOJ6356 四色灯(容斥+dp

    纪念第一次所有的解析全写在代码里面 QWQ 这里就简单说几句了 首先一个灯有贡献,当且仅当他被按了\(4k\)次. 那么我们定义\(f(S)\)表示\([1,n]\)中有多少个数\(x\)是集合\(S ...

  3. Java(27)集合二List

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15228435.html 博客主页:https://www.cnblogs.com/testero ...

  4. ❤️这应该是Postman最详细的中文使用教程了❤️(新手使用,简单明了)

    ️这应该是Postman最详细的中文使用教程了️(新手使用,简单明了) 在前后端分离开发时,后端工作人员完成系统接口开发后,需要与前端人员对接,测试调试接口,验证接口的正确性可用性.而这要求前端开发进 ...

  5. python socket zmq

    本篇博客将介绍zmq应答模式,所谓应答模式,就是一问一答,规则有这么几条 1. 必须先提问,后回答 2. 对于一个提问,只能回答一次 3. 在没有收到回答前不能再次提问 上代码,服务端: #codin ...

  6. 整数划分为k份

    题目 将整数n分成k份,且每份不能为空,任意两个方案不能相同(不考虑顺序). 例如:n=7,k=3,下面三种分法被认为是相同的. 1,1,5; 1,5,1; 5,1,1; 问有多少种不同的分法. 输入 ...

  7. 第2次 Beta Scrum Meeting

    本次会议为Beta阶段第2次Scrum Meeting会议 会议概要 会议时间:2021年5月31日 会议地点:「腾讯会议」线上进行 会议时长:0.5小时 会议内容简介:对完成工作进行阶段性汇报:对下 ...

  8. 主仆见证了 Hobo 的离别 题解

    前言: 题面挺神仙.反正我考试的时候看了40分钟也没看懂. 后来改题感觉自己写的挺假,没想到加个\(k==1\)的特判竟然就A了?无语力. 解析: 看懂题以后就好说了.首先这显然是一个树形结构.我们考 ...

  9. Netty:Netty的介绍以及它的核心组件(三)—— 事件和ChannelHandler

    Netty 使用异步事件驱动(Asynchronous Event-Driven)的应用程序范式,因此数据处理的管道(ChannelPipeLine)是经过处理程序(ChannelHandler)的事 ...

  10. QT判断文件/目录是否存在

    最近在用qt写一个ui,遇到删除sd卡中的文件失败情况,有些时候是存在删除链表里面的文件在sd卡上已经不存在了,导致失败,以为我的链表是定时刷新的,但是文件是实时更新会同步覆盖的.这样就存在可能上一秒 ...