zoukankan      html  css  js  c++  java
  • SP2713 GSS4 题解

    SP2713 GSS4 题解

    间隙

    双倍经验

    前置知识:线段树

    如果您还不会线段树的话,推荐去看一下这篇文章,我一开始也是在那里学的

    大致题意

    给一堆数,有以下两个操作:

    • 给出一个区间([L,R]),把该区间内的每个数都开平方

    • 给出一个区间([L,R]),查询这个区间的每个数的和

    分析

    首先看一下这个数据范围,(1e18),直接暴力的话肯定会T飞

    求和操作很简单,相信学过线段树的人应该都会

    难点在于这个开方操作,我们没法像线段树模板那样打个懒标记来进行下传操作

    通过观察(sqrt x)函数图像缓慢的增长率或者其他性质不难发现,很多开方操作是不必要的,考虑减枝优化:

    • 不难发现,当一个区间内的所有数都是(1)时,再对该区间进行开方操作对该区间内的总值造成不了任何改变((sqrt{1} = 1))

    因此代码实现方面只要在区间内总值均为1的情况下加一个小剪枝即可


    代码实现

    思路理解了代码实现难度就不高了,但还是有几个坑点...具体的注释里有写

    #include<bits/stdc++.h>
    #define lson (node<<1)//左儿子
    #define rson (node<<1|1)//右儿子
    #define ll long long 
    #define int long long //记得开long long
    using namespace std;
    const int MAXN = 100005;
    struct st{
    	int l,r;//左右端点
    	ll sum;
    }tree[MAXN<<2];
    
    ll a[MAXN];
    int n,m;
    void pushup(int node){
    	tree[node].sum = tree[lson].sum + tree[rson].sum;//合并操作
    }
    void build(int node,int l,int r){//建树
    	tree[node].l = l;
    	tree[node].r = r;
    	if(l==r){
    		tree[node].sum = a[l];
    		return;
    	}
    	int mid = (l+r)>>1;
    	build(lson,l,mid);
    	build(rson,mid+1,r);
    	pushup(node);
    }
    void change(int node,int l,int r){
    	int L = tree[node].l,R = tree[node].r;
    	if(tree[node].sum==R-L+1) return;//如果总和为区间长度,也就是所有值均为1时,直接剪枝掉
    	if(L==R){
    		tree[node].sum = sqrt(tree[node].sum);
    		return;
    	}
    	int mid = (L+R)>>1;
    	if(l<=mid){
    			change(lson,l,r);
    	}
    	if(r>mid){
    			change(rson,l,r);
    	}
    	pushup(node);
    }
    ll query(int node,int l,int r){//查询
    	int L = tree[node].l,R = tree[node].r;
    	if(l<=L&&r>=R){//包含在查询区间内,直接返回sum值
    		return tree[node].sum;
    	}
    	int mid = (L+R)>>1;
    	ll ans = 0;
    	if(l<=mid){
    		ans+=query(lson,l,r);
    	}
    	if(r>mid){
    		ans+=query(rson,l,r);
    	}
    	return ans;
    }
    signed main(){
    	ios::sync_with_stdio(false);//不加貌似会TLE?
        cin.tie(0);
        cout.tie(0);
    	int Case=0;
    	while(cin>>n){
    	printf("Case #%d:
    ",++Case);//注意,样例里那个case是要输出的,一开始被这里卡了好久...
    	memset(a,0,sizeof(a));//记得要先memset
    	memset(tree,0,sizeof(tree));
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    	}
    	build(1,1,n);
    	cin>>m;
    	while(m--){
    		int mode,left,right;
    		cin>>mode>>left>>right;
    		if(left > right){
    			swap(left,right);
    		}
    		if(mode==0){
    			change(1,left,right);
    		}
    		else{
    			printf("%lld
    ",query(1,left,right));
    		}
    	 }
    	 puts("");//记得换行
    	}
    	
    }
    
  • 相关阅读:
    .net 5中配置Quartz集群
    .net 5中使用Quartz构建单机版定时任务器
    error: src refspec future does not match any
    .net core通过jenkins + gogs + docker实现自动化部署
    Format of the initialization string does not conform to specification starting at index 75
    .net core中解决vue使用axios请求接口时未携带cookie信息的处理
    .net core在Docker->Linux及Window平台环境变量的获取的兼容
    centos7.x中安装mysql
    使用docker部署.net core3.1时的Dockerfile写法(持续补充)
    ARTS-WEEK-019
  • 原文地址:https://www.cnblogs.com/xcxc82/p/13429877.html
Copyright © 2011-2022 走看看