Codeforces Round #546
Codeforces Round #546
A
大意
给了一本书有n章,然后每一章是第x到第y页,问看了k-1页时还有多少章没全读完
B
大意
有n个盖子,每个盖子底下有一个硬币,上面有一块石头,必须把石头移开才可以拿硬币。
每一秒可以移动到相邻格子或将当前格子上的一块石头移到任意其他格子,或者捡起硬币。
问从第k个盖子出发,拿到所有硬币需要多长时间。
分析
ans=(n+1+n+(n-1)+min(n-k,k-1))
C
给出两个矩阵A,B,每次可以对a的任意一个x*x的方阵进行行列对称变换,问A能否变成B
分析
很容易看出每个数字只能往左下或者右上变换,直接将矩阵旋转45°后分析每行数字是否相同即可。
D
给出一个n的排列a[i],然后给出m组数对(x,y),如果a[i]=x并且a[i+1]=y则可以交换a[i]和a[i+1],问a[n]最多向前移动几步。
分析
假设有数对(x,y)使a[n-1]=x,a[n]=y,那么此时有一定不会使答案更劣的方案交换a[n]与a[n-1]。
如果最大的i,a[i]可以和a[n]交换,那么a[i+1]~a[n-1]都可以和a[i]交换才能使i交换到a[n-1]。倒着按照题意模拟即可。
E
给出一个长度为n的序列a,和长度为n-1的序列b,要求维护两个操作
1.给出k,x,使a[k]=a[k]+x,同时对于i=k+1,若有a[k]+b[k]>a[i],则a[i]=a[i-1]+b[i-1],并且继续检查i+1直至i=n。
2.求和l~r
分析
求和明显比较简单,考虑如何维护修改操作,发现操作没有单调性也不具有可加性质,不好使用线段树直接进行维护。继续观察发现,第二个数列b并没有任何操作,所以如果有一个a[x]更新了它之后的一段区间,假设最后更新到y,那么x~y这段区间内的所有的数都可以由a[x]直接推导,即a[i]=a[x]+\(\sum_{j=x}^{i}b[j]\),使用前缀和优化即可O(1)得出。
接着考虑如果一段区间都是由一个数a[x]推导而来的话,当这一段数的第一个能够被一个新的数更新的时候,这一段数就一定都可以被这个新的数更新。可以发现随着修改操作的增加,这种可以连续更新的子段会越来越长,所以考虑分块。
首先对于每一个块记录两个值,即他们是被前面第几个数更新的(如果没有记为0)以及这个数的大小,同时记录这个块的和s。在进行修改操作时,暴力修改整个块,并且清空标记,接着询问之后的块,如果该块被打过标记,则比较块的第一个数的值和当前修改的值,如果可行的话直接整块修改,不可行的话直接break,如果没有打过标记,直接暴力修改,如果整个块都被暴力修改了,则给这个块打上标记。
复杂度方面,查询时明显是\(\sqrt{n}\),修改操作时,每次修改操作只会将一个标记清0,如果一次操作暴力了很多个块,明显会给多个块打上标记,使它们在之后的修改操作中只需要O(1),同时一次操作只能清0一个块,所以均摊时间复杂度依然是\(\sqrt{n}\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=2e5+7;
int sum[MAXN],a[MAXN],tag[MAXN],pre[MAXN],n,m,block,l[MAXN],r[MAXN],belong[MAXN];
int s[MAXN],ssum[MAXN],q,pres[MAXN];
inline void change(int x,int k)
{
int f=0;
if(tag[belong[x]]){
for(int i=l[belong[x]];i<=r[belong[x]];i++){
a[i]=pres[belong[x]]+sum[i]-sum[pre[belong[x]]];
}
tag[belong[x]]=0;
pre[belong[x]]=0;
pres[belong[x]]=0;
}
a[x]=a[x]+k;
for(int i=x+1;i<=r[belong[x]];i++){
if(a[i]<a[x]+sum[i]-sum[x]){
a[i]=a[x]+sum[i]-sum[x];
} else{
f=1;
break;
}
}
s[belong[x]]=0;
for(int i=l[belong[x]];i<=r[belong[x]];i++) s[belong[x]]+=a[i];
if(f==1) return;
for(int i=belong[x]+1;i<=belong[n];i++){
int flag=0;
if(tag[i]){
if(pres[i]+sum[l[i]]-sum[pre[i]]<a[x]+sum[l[i]]-sum[x]){
pre[i]=x;
pres[i]=a[x];
s[i]=(r[i]-l[i]+1)*a[x]+(ssum[r[i]]-ssum[l[i]-1]-sum[x]*(r[i]-l[i]+1));
} else {
flag=1;
break;
}
} else {
for(int j=l[i];j<=r[i];j++){
if(a[j]<a[x]+sum[j]-sum[x]){
s[i]-=a[j];
a[j]=a[x]+sum[j]-sum[x];
s[i]+=a[j];
} else {
flag=1;
break;
}
}
if(flag){
break;
} else {
tag[i]=1;
pre[i]=x;
pres[i]=a[x];
}
}
}
}
inline int query(int L,int R)
{
int res=0;
if(belong[L]==belong[R]){
if(tag[belong[L]]){
for(int i=L;i<=R;i++) res+=pres[belong[i]]+(sum[i]-sum[pre[belong[i]]]);
} else {
for(int i=L;i<=R;i++) res+=a[i];
}
} else {
for(int i=L;i<=r[belong[L]];i++){
if(tag[belong[L]]) res+=pres[belong[L]]+(sum[i]-sum[pre[belong[L]]]);
else res+=a[i];
}
for(int i=belong[L]+1;i<belong[R];i++){
res+=s[i];
}
for(int i=l[belong[R]];i<=R;i++){
if(tag[belong[R]]) res+=pres[belong[R]]+(sum[i]-sum[pre[belong[R]]]);
else res+=a[i];
}
}
return res;
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=2;i<=n;i++){
int x;
cin>>x;
sum[i]=sum[i-1]+x;
ssum[i]=ssum[i-1]+sum[i];
}
block=sqrt(n);
for(int i=1;i<=n;i++) belong[i]=i/block+1;
for(int i=1;i<=n;i++) if(!l[belong[i]]) l[belong[i]]=i;
for(int i=n;i;i--) if(!r[belong[i]]) r[belong[i]]=i;
for(int i=1;i<=belong[n];i++){
for(int j=l[i];j<=r[i];j++) s[i]+=a[j];
}
cin>>q;
while(q--){
char opt;
cin>>opt;
if(opt=='s'){
int L,R;
cin>>L>>R;
int ans=query(L,R);
printf("%lld\n",ans);
} else {
int x,k;
cin>>x>>k;
change(x,k);
}
}
}