感觉我数据结构有些弱,最近开始练习难道为2300~2700的数据结构题。
首先我们发现,lucky number不会太多,最多就是\((2^1+2^2+2^3+2^4+1)=31\)个(最后加\(1\)是对于所有\(x>7777\)的数,最近的lucky number应该是\(44444\))
这里我们维护的东西有些奇特——我们维护\(val_{i}=L-a_{i}\)的值,其中\(L\)是大于等于\(a_{i}\)最小的lucky number。
那么区间加上\(D\)就相当于区间将\(val\)减去\(D\)。
但是有可能存在\(val_{i}<D\)的情况,那么我们此时记录这样的位置,并且计算当前\(a_{i}\)的值,暴力重新更新\(L'-a_{i}\),此时\(L'\)是下一个大于等于\(a_{i}\)的值。(线段树单点修改)
看起来直接记录每个\(val_{i}<D\)的点是\(O(n)\)的,但事实上,我们每次更新都会使得\(L\)变大,而最大也就是\(L=44444\),即每个点只会暴力更新\(30\)次,故总世界复杂度为\(O(30q\log n)\)。
如何找到\(val_{i}<D\)的点?我们可以记录区间最小值,若最小值\(<D\),那么意味着这个区间内一定有一个\(<D\)的点,继续递归即可。
如何回答询问?我们在线段树上不仅记录最小值,并且记录有多少个最小值。询问本质就是找到最小值为0的个数。
注意常数。
#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl
const int maxn=100005;
int n,q,a[maxn],now[maxn];
int nxt[10005],val[maxn<<2],lef[maxn<<2],rig[maxn<<2],sum[maxn<<2],lzy[maxn<<2];
char buf[12];
std::vector<int> need;
void pushdown(int pos) {
val[pos<<1]+=lzy[pos];
val[pos<<1|1]+=lzy[pos];
lzy[pos<<1]+=lzy[pos];
lzy[pos<<1|1]+=lzy[pos];
lzy[pos]=0;
}
void pushup(int pos) {
if(val[pos<<1]<val[pos<<1|1]) {
val[pos]=val[pos<<1];
sum[pos]=sum[pos<<1];
} else if(val[pos<<1]>val[pos<<1|1]) {
val[pos]=val[pos<<1|1];
sum[pos]=sum[pos<<1|1];
} else {
val[pos]=val[pos<<1];
sum[pos]=sum[pos<<1]+sum[pos<<1|1];
}
}
void build(int pos,int l,int r) {
lef[pos]=l,rig[pos]=r;
if(l==r) {
val[pos]=nxt[a[l]]-a[l];
sum[pos]=1;
now[l]=nxt[a[l]];
} else {
int m=l+r>>1;
build(pos<<1,l,m); build(pos<<1|1,m+1,r);
pushup(pos);
}
}
void get_change(int l,int r,int D,int pos) {
if(l<=lef[pos]&&rig[pos]<=r) {
if(val[pos]<D) {
if(lef[pos]==rig[pos]) {
need.push_back(lef[pos]);
return;
}
pushdown(pos);
get_change(l,r,D,pos<<1);
get_change(l,r,D,pos<<1|1);
pushup(pos);
}
} else if(l<=rig[pos]&&r>=lef[pos]) {
pushdown(pos);
get_change(l,r,D,pos<<1);
get_change(l,r,D,pos<<1|1);
pushup(pos);
}
}
int query(int p,int pos) {
if(lef[pos]==rig[pos]) return val[pos];
pushdown(pos); int ret;
if(rig[pos<<1]>=p) ret=query(p,pos<<1);
else ret=query(p,pos<<1|1);
pushup(pos); return ret;
}
void update(int l,int r,int D,int pos) {
if(l<=lef[pos]&&rig[pos]<=r) {
val[pos]+=D;
lzy[pos]+=D;
} else if(l<=rig[pos]&&r>=lef[pos]) {
pushdown(pos);
update(l,r,D,pos<<1);
update(l,r,D,pos<<1|1);
pushup(pos);
}
}
int get_answer(int l,int r,int pos) {
if(l<=lef[pos]&&rig[pos]<=r) {
if(val[pos]==0) {
return sum[pos];
}
} else if(l<=rig[pos]&&r>=lef[pos]) {
pushdown(pos);
int ret=get_answer(l,r,pos<<1)+get_answer(l,r,pos<<1|1);
pushup(pos);
return ret;
}
return 0;
}
int main() {
std::vector<int> lucky;
for(int i=1;i<=4;i++) {
for(int j=0;j<(1<<i);j++) {
int num=0;
for(int k=0;k<i;k++) {
if(j&(1<<k)) {
num=10*num+4;
} else {
num=10*num+7;
}
}
lucky.push_back(num);
}
}
lucky.push_back(44444);
std::sort(lucky.begin(),lucky.end());
for(int i=1;i<=10000;i++) {
nxt[i]=*std::lower_bound(lucky.begin(),lucky.end(),i);
}
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
}
build(1,1,n);
while(q--) {
scanf("%s",buf);
int op=strlen(buf)==5;
if(op==0) {
int l,r,x; scanf("%d%d%d",&l,&r,&x);
need.clear();
get_change(l,r,x,1);
for(auto item : need) {
int rec=query(item,1);
int num=now[item]-rec;
update(item,item,-rec+nxt[num+x]-num,1);
now[item]=nxt[num+x];
}
update(l,r,-x,1);
} else {
int l,r; scanf("%d%d",&l,&r);
printf("%d\n",get_answer(l,r,1));
}
}
return 0;
}
标签:number,val,int,lucky,Codeforces,121,pos,pushdown
From: https://www.cnblogs.com/Nastia/p/16584637.html