其他分享
首页 > 其他分享> > Codeforces 121 E

Codeforces 121 E

作者:互联网

感觉我数据结构有些弱,最近开始练习难道为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
来源: https://www.cnblogs.com/Nastia/p/16584637.html