zoukankan      html  css  js  c++  java
  • 「CF438D The Child and Sequence」

    一道CF线段树好题.

    前置芝士

    1. 线段树:一个很有用数据结构.
    2. 势能分析:用来证明复杂度,其实不会也没什么关系啦.

    具体做法

    不难发现,对于一个数膜一个大于它的数后,这个数至少减少一半,每个数最多只能被膜(log_2N)次,所以就可以暴力修改了,如果当前子树的最大值也比膜数要大,那这个膜数肯定就没什么用了,所以可以再记录一个区间最大值.

    代码

    #include<bits/stdc++.h>
    #define rap(i,first,last) for(int i=first;i<=last;++i)
    #define Lson (now<<1)
    #define Rson (now<<1|1)
    #define Middle ((left+right)>>1)
    #define Left Lson,left,Middle
    #define Right Rson,Middle+1,right
    #define Now nowleft,nowright
    using namespace std;
    const int maxN=114514;
    int N,M;
    struct Tree
    {
    	//注意开long long
    	long long max,sum;//线段树维护区间max和区间和
    }tree[maxN*4];
    long long arr[maxN];
    long long maxll(long long a,long long b)//手写max
    {
    	if(a>b)return a;
    	return b;
    }
    void PushUp(int now)//合并的部分
    {
    	tree[now].sum=tree[Lson].sum+tree[Rson].sum;
    	tree[now].max=maxll(tree[Lson].max,tree[Rson].max);
    }
    void Build(int now=1,int left=1,int right=N)//建树部分
    {
    	if(left==right)
    	{
    		tree[now].max=tree[now].sum=arr[left];//直接赋值
    		return;
    	}
    	Build(Left);
    	Build(Right);
    	PushUp(now);//建完子树后合并
    }
    void UpDataAdd(int num,int add,int now=1,int left=1,int right=N)
    //单点覆盖操作(不要问为什么是Add,哎....)
    {
    	if(num<left||num>right)return;
    	if(left==right)
    	{
    		tree[now].max=add;//直接赋值
    		tree[now].sum=add;
    		return;
    	}
    	//没有PushDown
    	UpDataAdd(num,add,Left);
    	UpDataAdd(num,add,Right);
    	PushUp(now);
    }
    void UpDataMod(int nowleft,int nowright,int mod,int now=1,int left=1,int right=N)
    //暴力取膜
    {
    	if(nowright<left||right<nowleft)return;
    	if(tree[now].max<mod)return;//已经没有用了
    	if(left==right)//叶节点暴力取膜
    	{
    		tree[now].max%=mod;
    		tree[now].sum%=mod;
    		return;
    	}
    	UpDataMod(Now,mod,Left);
    	UpDataMod(Now,mod,Right);
    	PushUp(now);
    }
    long long Query(int nowleft,int nowright,int now=1,int left=1,int right=N)//查询区间和
    {
    	if(nowright<left||right<nowleft)return 0;
    	if(nowleft<=left&&right<=nowright)
    	{
    		return tree[now].sum;
    	}
    	return Query(Now,Left)+Query(Now,Right);
    }
    int main()
    {
    	scanf("%d%d",&N,&M);
    	rap(i,1,N)scanf("%lld",&arr[i]);
    	Build();
    	int check,left,right,mod;
    	rap(i,1,M)
    	{
    		scanf("%d%d%d",&check,&left,&right);
    		if(check==1)
    		{
    			printf("%lld
    ",Query(left,right));
    		}
    		if(check==2)
    		{
    			scanf("%d",&mod);
    			UpDataMod(left,right,mod);//直接修改
    		}
    		if(check==3)
    		{
    			UpDataAdd(left,right);//直接修改就行了啊
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    随笔35 内联函数
    随笔32 内部类,外部类,局部内部类
    随笔31 Spring的依赖注入的三种方式
    随笔30 抽象类与接口
    随笔29 Statement对象
    随笔28 Spring中的事务
    随笔27 面向对象的五大基本原则
    随笔26 java中的泛型
    html5学习笔记——HTML5 web存储
    html5学习笔记——HTML 5 视频
  • 原文地址:https://www.cnblogs.com/Sxy_Limit/p/12207278.html
Copyright © 2011-2022 走看看