传送门:bzoj5286
题解
考虑是个环,把
T
T
T数组双倍复制一下,得到:
a
n
s
=
m
i
n
i
=
1
n
(
m
a
x
j
=
i
i
+
n
−
1
(
T
j
−
(
j
−
i
)
)
)
+
n
−
1
ans=min_{i=1}^n (max_{j=i} ^{i+n-1}(T_j-(j-i)))+n-1
ans=mini=1n(maxj=ii+n−1(Tj−(j−i)))+n−1
证明:
当 m a x i = 1 n T i < 2 × ( n − 1 ) max_{i=1}^n T_i<2\times (n-1) maxi=1nTi<2×(n−1)时,显找到最小的差 m i n i = 1 n ( m a x j = i i + n − 1 ( T j − ( j − i ) ) ) min_{i=1} ^n(max_{j=i}^{i+n-1}(T_j-(j-i))) mini=1n(maxj=ii+n−1(Tj−(j−i)))后在起点等待这么久后,就可以畅通无阻地走完一圈,而答案是最优的。
当
m
a
x
i
=
1
n
T
i
≥
2
×
(
n
−
1
)
max_{i=1}^n T_i\geq 2\times (n-1)
maxi=1nTi≥2×(n−1)时,从某一起点出发,有可能先走完一圈其他点后再绕回这个最大点,答案最优,而如果按照上面的式子算,显然不是最优的(这也是问题所在,如下图(出发点为蓝点,红点
T
i
≥
2
×
(
n
−
1
)
T_i\geq 2\times(n-1)
Ti≥2×(n−1)))。
考虑在走完一圈后,红蓝之间的点显然是多走了一次的,而这些时间应该包含在等待
T
m
a
x
T_{max}
Tmax中,而不是额外再算,但完全可以从绿点出发,对于绿点来说,先走和后走就没什么区别了,上式也就满足了最优。
故对于所有情况,都存在上式可以取到最优解。
再观察枚举起点后的取答案: m a x j = i i + n − 1 ( T j − ( j − i ) ) max_{j=i}^{i+n-1}(T_j-(j-i)) maxj=ii+n−1(Tj−(j−i))
实际上等价于
m
a
x
j
=
i
2
n
(
T
j
−
j
)
+
i
max_{j=i}^{2n}(T_j-j)+i
maxj=i2n(Tj−j)+i,因为显然
T
i
−
i
>
T
i
+
n
−
(
i
+
n
)
(
T
i
=
T
i
+
n
,
1
≤
i
≤
n
)
T_i-i>T_{i+n}-(i+n)(T_i=T_{i+n},1\leq i\leq n)
Ti−i>Ti+n−(i+n)(Ti=Ti+n,1≤i≤n),这样化简后等价于求一个后缀最大,处理出
x
i
=
m
a
x
j
=
i
2
n
(
T
j
−
j
)
x_i=max_{j=i}^{2n} (T_j-j)
xi=maxj=i2n(Tj−j),则
a
n
s
=
m
i
n
i
=
1
n
(
x
i
+
i
)
+
n
−
1
ans=min_{i=1}^n (x_i+i)+n-1
ans=mini=1n(xi+i)+n−1。
没有修改的询问直接
O
(
n
)
O(n)
O(n)查询即可。
有修改的询问用线段树优化。
考虑线段树如何优化单调队列:
线段树节点
k
k
k(管辖范围
[
l
,
r
]
[l,r]
[l,r])上存两个信息:
m
x
k
,
v
a
l
k
mx_k,val_k
mxk,valk。
m
x
k
=
m
a
x
i
=
l
r
(
T
i
−
i
)
,
v
a
l
k
=
m
i
n
i
=
l
m
i
d
(
x
i
+
i
)
(
x
i
=
m
a
x
j
=
i
r
(
T
j
−
j
)
)
mx_k=max_{i=l}^r (T_i-i),val_k=min_{i=l}^{mid}(x_i+i)\ (x_i=max_{j=i}^r (T_j-j))
mxk=maxi=lr(Ti−i),valk=mini=lmid(xi+i) (xi=maxj=ir(Tj−j))
(线段树根节点范围为
[
1
,
2
n
]
[1,2n]
[1,2n],查询直接回答
v
a
l
r
o
o
t
+
n
−
1
val_{root}+n-1
valroot+n−1)。
考虑如何 p u s h u p pushup pushup:
设当前节点为 k k k(管辖区间为 [ l , r ′ ] [l,r'] [l,r′]),左儿子为 l s ls ls(管辖区间为 [ l , r ] [l,r] [l,r]),右儿子为 r s rs rs(管辖区间为 [ r + 1 , r ′ ] [r+1,r'] [r+1,r′])。
m x k = m a x ( m x l s , m x r s ) mx_k=max(mx_{ls},mx_{rs}) mxk=max(mxls,mxrs)
对于 v a l k = m i n i = l r ( x i + i ) val_k=min_{i=l}^r (x_i+i) valk=mini=lr(xi+i),由 l s ls ls可得 m i n i = l m i d ( x i + i ) min_{i=l} ^ {mid} (x_i+i) mini=lmid(xi+i),而 m i n i = m i d + 1 r ( x i + i ) min_{i=mid+1}^{r} (x_i+i) mini=mid+1r(xi+i),通过 q u e r y ( n w , m x x , l , r ) query(nw,mxx,l,r) query(nw,mxx,l,r)递归得到(底层为 m a x ( m x n w , m x x ) max(mx_{nw},mxx) max(mxnw,mxx)),分类讨论一下 q u e r y ( l s , m x r s , l , r ) query(ls,mx_{rs},l,r) query(ls,mxrs,l,r):
-
m x l s r s ≥ m x r s mx_{ls_{rs}}\geq mx_{rs} mxlsrs≥mxrs时, v a l l s l s val_{ls_{ls}} vallsls不变,只需要修改 l s r s ls_{rs} lsrs,返回 m i n ( v a l l s , q u e r y ( l s r s , m x r s , m i d + 1 , r ) ) min(val_{ls},query(ls_{rs},mx_{rs},mid+1,r)) min(valls,query(lsrs,mxrs,mid+1,r))
-
m x l s r s < m x r s mx_{ls_{rs}}<mx_{rs} mxlsrs<mxrs时, v a l l s val_{ls} valls整个都会统一增大,但不确定 m x l s l s mx_{ls_{ls}} mxlsls与 m x r s mx_{rs} mxrs的关系,返回 m i n ( m i d + 1 + m x r s , q u e r y ( l s l s , m x r s , l , m i d ) ) min(mid+1+mx_{rs},query(ls_{ls},mx_{rs},l,mid)) min(mid+1+mxrs,query(lsls,mxrs,l,mid))
复杂度 O ( ( n + m ) l o g 2 n ) O((n+m)log^2 n) O((n+m)log2n)
代码
#include<bits/stdc++.h>
#define gc getchar
#define si isdigit
#define mid (((l)+(r))>>1)
#define lc k<<1
#define rc k<<1|1
using namespace std;
const int N=2e5+100;
int n,m,a[N],op,ans;
int mx[N<<2],val[N<<2];
char c;
inline int rd()
{
c=gc();int x=0;
for(;!si(c);c=gc());
for(;si(c);c=gc()) x=x*10+(c^48);
return x;
}
inline int get(int ql,int mxx,int l,int r)
{
if(l==r) return max(mx[ql],mxx)+l;
if(mx[ql<<1|1]>=mxx) return min(val[ql],get(ql<<1|1,mxx,mid+1,r));
return min(mid+1+mxx,get(ql<<1,mxx,l,mid));
}
inline void update(int k,int l,int r)
{
mx[k]=max(mx[lc],mx[rc]);
val[k]=get(lc,mx[rc],l,mid);
}
inline void build(int k,int l,int r)
{
if(l==r){val[k]=a[l]+l;mx[k]=a[l];return;}
build(lc,l,mid);build(rc,mid+1,r);
update(k,l,r);
}
inline void change(int k,int l,int r,int pos)
{
if(l==r) {val[k]=a[l]+l;mx[k]=a[l];return;}
if(pos<=mid) change(lc,l,mid,pos);
else change(rc,mid+1,r,pos);
update(k,l,r);
}
inline void out(int x){if(x>9) out(x/10);putchar('0'+x%10);}
int main(){
int i,j,x,y;
n=rd();m=rd();op=rd();
for(i=1;i<=n;++i){a[i]=rd()-i;a[i+n]=a[i]-n;}
build(1,1,n<<1);
out((ans=val[1]+n-1));puts("");
for(;m;--m){
x=rd();y=rd();
if(op) x^=ans,y^=ans;
a[x]=y-x;a[x+n]=y-x-n;
change(1,1,n<<1,x);change(1,1,n<<1,x+n);
out((ans=val[1]+n-1));puts("");
}
}