称序列$\{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. 实现一个简单的侧边导航Winform程序框架

    目录 简介 实现导航面板 实现方法 使用方法 实现标题栏 窗体拖拽及最大化 自定义窗体按钮 标题显示 按钮设置 实现状态栏 整体使用 参考文章 简介 每次新项目都要想着界面怎么设计好,但想来想去上位机 ...

  2. Linux下iptables学习笔记

    Linux下iptables学习笔记 在Centos7版本之后,防火墙应用已经由从前的iptables转变为firewall这款应用了.但是,当今绝大多数的Linux版本(特别是企业中)还是使用的6. ...

  3. Firewalls命令行配置

    1.指定端口开放查询.开放.关闭端口 # 查询端口是否开放 firewall-cmd --query-port=8080/tcp # 开放80端口 firewall-cmd --permanent - ...

  4. Serverless 解惑——函数计算如何安装字体

    前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute):函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算准 ...

  5. The type name or alias SqlServer could not be resolved.Please check your configuration

    The type name or alias SqlServer could not be resolved.Please check your configuration file.... 检查一下 ...

  6. Python | 一键生成九宫格图片

    一键生成九宫格图片 首先我们准备几张图片: 将代码文件放在放置图片的地方,用软件打开: 点击运行,在当前目录下会生成一个文件夹: 打开新生成的文件夹: 打开对应图片的名称文件夹: 如果不想图片被分成9 ...

  7. 每日总结:Java课堂测试第三阶段第一次优化 (2021.9.20)

    package jisuan2; import java.util.*;public class xiaoxue { public static void main(String[] args) { ...

  8. 洛谷3628 APIO2010特别行动队(斜率优化)

    考虑最普通的\(dp\) \[dp[i]=max(dp[j]+a*(sum[i]-sum[j])^2+b*(sum[i]-sum[j])+c \] qwq 由于演算纸扔掉了 qwq 所以直接给出最后的 ...

  9. 详解python三大器——迭代器、生成器、装饰器

    迭代器 聊迭代器前我们要先清楚迭代的概念:通常来讲从一个对象中依次取出数据,这个过程叫做遍历,这个手段称为迭代(重复执行某一段代码块,并将每一次迭代得到的结果作为下一次迭代的初始值). 可迭代对象(i ...

  10. 基于JWT的Token身份验证

    ​ 身份验证,是指通过一定的手段,完成对用户身份的确认.为了及时的识别发送请求的用户身份,我们调研了常见的几种认证方式,cookie.session和token. 1.Cookie ​ cookie是 ...