称序列$\{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. 拥抱开源,共建生态 - 开源生态与效能提升专场 | CIF 精彩看点

    随着软件技术日新月异的发展,GitHub 已经进化成为人类软件的基因库,遇到问题第一时间在 GitHub 上寻求合适的解决方案,已经逐渐变成工程师处理问题的常见方法.据 GitHub 年度报告显示,2 ...

  2. 《手把手教你》系列技巧篇(二十九)-java+ selenium自动化测试- Actions的相关操作上篇(详解教程)

    1.简介 有些测试场景或者事件,Selenium根本就没有直接提供方法去操作,而且也不可能把各种测试场景都全面覆盖提供方法去操作.比如:就像鼠标悬停,一般测试场景鼠标悬停分两种常见,一种是鼠标悬停在某 ...

  3. Linear Referencing Tools(线性参考工具)

    线性参考工具 # Process: 创建路径 arcpy.CreateRoutes_lr("", "", 输出路径要素类, "LENGTH" ...

  4. 题解 「BZOJ3636」教义问答手册

    题目传送门 Description 作为泉岭精神的缔造者.信奉者.捍卫者.传承者,Pear决定印制一些教义问答手册,以满足泉岭精神日益增多的信徒.Pear收集了一些有关的诗选.语录,其中部分内容摘录在 ...

  5. 未来云原生 | CIF 论坛精彩看点

    当下云原生技术正在飞速发展,那么如何准确理解「云原生」?在发展不够成熟,行业认知差异大的情况下,不论是云原生计算基金会(CNCF),还是行业的任何大咖,都不能给出精确的.便于理解的定义.我们要理解的逻 ...

  6. Spark解决SQL和RDDjoin结果不一致问题(工作实录)

    问题描述:DataFrame的join结果不正确,dataframeA(6000无重复条数据) join dataframeB(220条无重复数据,由dataframeA转化而来,key值均源于dat ...

  7. python收集参数与解包

    收集任意数量的实参 def make_pizza(*toppings): """打印顾客点的所有配料""" print(toppings) ...

  8. Spring session redis ERR unknown command 'CONFIG'

    部署线上服务启动报错 redis.clients.jedis.exceptions.JedisDataException: ERR unknown command 'CONFIG' Redis CON ...

  9. Django+Vue跨域配置与经验

    一.原理 同源?同源策略? 同源的定义是:两个页面的协议.端口和域名都相同 同源的例子: 不同源的例子: 同源策略SOP(Same origin policy)是一种浏览器约定,它是浏览器最核心也最基 ...

  10. Java并发:重入锁 ReentrantLock(一)

    ReentrantLock 是一种可重入的互斥锁,它不像 synchronized关键字一样支持隐式的重进入,但能够使一个线程(不同的方法)重复对资源的重复加锁而不受阻塞. ReentrantLock ...