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;
    }
    
  • 相关阅读:
    R语言初涉
    Android源码大全
    Centos关闭防火墙
    Java开发常用下载的网址
    linux下解压命令大全
    Android常见布局问题
    配置Nutch模拟浏览器以绕过反爬虫限制
    Nutch的发展历程
    用三层交换机当路由器——最复杂的网络拓扑结构
    Ant 简易教程
  • 原文地址:https://www.cnblogs.com/Sxy_Limit/p/12207278.html
Copyright © 2011-2022 走看看