zoukankan      html  css  js  c++  java
  • codeforces 679e Bear and Bad Powers of 42

    传送门:http://codeforces.com/contest/679/problem/E

    题目意思很清晰,给你一个序列,要求你完成以下三个操作:

    1.输出A[i]

    2.将[a,b]区间的所有数字变成c

    3.将[a,b]区间的每个数加上c,若此时区间内有42的整次幂(1,42,422,423,424...),则一直进行此操作,直到区间内没有这类数;

    正解:

    线段树拓展题目;

    先不考虑操作2,只考虑操作3;

    我可以给每个数字设置一个等级,即处在(1,42)的数1级,(42,422)的数2级,以此类推,再记录每个数与它最近的大于它的42的整次幂的距离;

    用线段树记录区间最大值,一旦最大值大于0,对线段树向下走,暴力升级,即哪里的最大值大于0,就去哪里升级,由于指数上升很快,每个数最多被升级log42(数值范围)次;

    再考虑操作2,操作2会将一整个区间变成一个数,这时如果暴力升级可能会被卡掉,不如在线段树里记录一下,这段区间的数是否相同,如果相同,对整段区间进行升级即可,没必要再下去了;

    考虑一下时间复杂度,操作3的复杂度由于指数的保证,均摊不会超过O(log22n),操作2复杂度相当,操作1复杂度O(logn),总复杂度O(nlog22n),过掉这道题还是比较轻松的;

    对于这道题需要注意的是,lazy标记的下传,需要头脑十分清晰;

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<cstdlib>
    #include<ctime>
    #include<algorithm>
    using namespace std;
    #define mid ((l+r)>>1)
    #define LL long long
    #define FILE "dealing"
    #define up(i,j,n) for(LL i=(j);i<=(n);i++)
    #define pii pair<LL,LL>
    LL read(){
    	LL x=0,f=1,ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return f*x;
    }
    const LL maxn=1000100,inf=1000000000000000LL,mod=998244353;
    LL n,m,a[maxn];
    LL x,y,c;
    LL f[maxn],d[maxn],g[maxn],del[maxn],Max[maxn],mi[20],flag[maxn],level;
    pii ch(LL x){up(i,0,11)if(x<mi[i])return make_pair(i,x-mi[i]);}
    void upp(LL o){
    	while(f[o]>0){
    		g[o]++;
    		Max[o]=f[o]=Max[o]+mi[g[o]-1]-mi[g[o]];	
    	}
    }
    void pushdown(LL x){
    	if(del[x]){
    		Max[x<<1]+=del[x],Max[x<<1|1]+=del[x];
    		if(d[x<<1])f[x<<1]+=del[x],upp(x<<1);
    		else del[x<<1]+=del[x];
    		if(d[x<<1|1])f[x<<1|1]+=del[x],upp(x<<1|1);
    		else del[x<<1|1]+=del[x];
    		del[x]=0;
    	}
    	if(d[x]){
    		Max[x<<1]=Max[x<<1|1]=f[x];
    		del[x<<1]=del[x<<1|1]=0;
    		g[x<<1]=g[x<<1|1]=g[x];
    		d[x<<1]=d[x<<1|1]=1;
    		f[x<<1]=f[x<<1|1]=f[x];
    		d[x]=0;f[x]=0;
    	}
    }
    void updata(LL x){
    	Max[x]=max(Max[x<<1],Max[x<<1|1]);
    	g[x]=(Max[x<<1]>Max[x<<1|1])?g[x<<1]:g[x<<1|1];
    	if(flag[x<<1]&&flag[x<<1|1]&&Max[x<<1]==Max[x<<1|1]&&g[x<<1]==g[x<<1|1])flag[x]=1;
    	else flag[x]=0;
    }
    LL query(LL l,LL r,LL o){//求[x,y]区间最大值
    	if(l>y||r<x)return -inf;
    	if(l>=x&&r<=y){level=g[o];return Max[o];}
    	pushdown(o);
    	return max(query(l,mid,o<<1),query(mid+1,r,o<<1|1));
    }
    void change(LL l,LL r,LL o){//将[x,y]区间赋为c
    	if(l>y||r<x)return;
    	if(l>=x&&r<=y){
    		d[o]=1;flag[o]=1;
    		del[o]=0;
    		pii x=ch(c);
    		f[o]=x.second;
    		Max[o]=x.second;
    		g[o]=x.first;
    		return;
    	}
    	pushdown(o);
    	change(l,mid,o<<1);
    	change(mid+1,r,o<<1|1);
    	updata(o);
    }
    void Change(LL l,LL r,LL o){//将[x,y]区间加c
    	if(l>y||r<x)return;
    	if(l>=x&&r<=y){
    		Max[o]+=c;
    		if(d[o]){
    			f[o]+=c;
    			if(f[o]>0){
    				while(Max[o]>0){
    				g[o]++;
    				Max[o]=f[o]=Max[o]+mi[g[o]-1]-mi[g[o]];
    				}
    			}
    		}
    		else del[o]+=c;
    		return;
    	}
    	pushdown(o);
    	Change(l,mid,o<<1);
    	Change(mid+1,r,o<<1|1);
    	updata(o);
    }
    void upgrade(LL l,LL r,LL o){//将[1,n]中的所有点升级
    	if(flag[o]){
    		d[o]=1;
    		while(Max[o]>0){
    		g[o]++;
    		f[o]=Max[o]=Max[o]+mi[g[o]-1]-mi[g[o]];
    		}
    		return;
    	}
    	pushdown(o);
    	if(Max[o<<1]>0)upgrade(l,mid,o<<1);
    	if(Max[o<<1|1]>0)upgrade(mid+1,r,o<<1|1);
    	updata(o);
    }
    void build(LL l,LL r,LL o){
    	if(l==r){
    		flag[o]=1;
    		pii x=ch(a[l]);
    		Max[o]=x.second;
    		g[o]=x.first;
    		flag[o]=1;
    		return;
    	}
    	build(l,mid,o<<1);
    	build(mid+1,r,o<<1|1);
    	updata(o);
    }
    int main(){
    	n=read();m=read();
    	mi[0]=1;
    	up(i,1,11)mi[i]=mi[i-1]*42;
    	up(i,1,n)a[i]=read();
    	build(1,n,1);
    	while(m--){
    		LL ch=read();
    		if(ch==1){
    			y=x=read();
    			printf("%lld
    ",query(1,n,1)+mi[level]);
    		}
    		if(ch==2){
    			x=read(),y=read(),c=read();
    			change(1,n,1);
    		}
    		if(ch==3){
    			x=read(),y=read(),c=read();
    			do{
    				Change(1,n,1);
    				upgrade(1,n,1);
    				if(Max[1]<0)break;
    			}while(1);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    C#值类型和引用类型的不同
    C# new用法总结-转
    C#中New关键词的几种用法
    命令行客户端MySQL的使用(1)——Python
    数据库的基本使用——MySQL
    生成器的创建方式——Python
    with与“上下文管理器”——Python
    魔法属性——Python
    property属性——Python
    正则匹配之贪婪和非贪婪——Python
  • 原文地址:https://www.cnblogs.com/chadinblog/p/6336437.html
Copyright © 2011-2022 走看看