SP2713 GSS4 - Can you answer these queries IV /上帝造题的7分钟2 (区间开方)

题意

给出一个序列,有两种操作:对[l,r]的数开方(下取整),求[l,r]的区间和

不保证给出的区间[x, y] 有x <= y ,如果x>y,请交换x,y。

n,m<=100000

$\sum_{i=1}^{n}a_{i} \leq 1e18$

题解

上帝造题的7分钟2很早之前写过了,发现双倍经验而且这道题也有点意思,就写了这篇博客。

区间求和+区间修改显然线段树可以,那么怎样区间开方,这个其实是不好维护的。考虑暴力——单点修改,每个点最多被修改10次左右吧就可以变成1就不需要被改了,那我们就需要保证不去不需要被修改的点,这个用区间和与区间长度就可以看出了。

 

SP2713 GSS4 - Can you answer these queries IV  /上帝造题的7分钟2 (区间开方)
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;

#define ls rt<<1
#define rs rt<<1|1
#define mid ((l+r)>>1)

const int maxn=100005;
int n,m,a_l,a_r;
long long sum[maxn<<2],a[maxn];

void swap(int &x,int &y){
  int t=x;
  x=y;
  y=t;
}

void update(int rt){
    sum[rt]=sum[ls]+sum[rs];
}

void build(int rt,int l,int r){
    if(l==r){sum[rt]=a[l];return ;}
    build(ls,l,mid);build(rs,mid+1,r);
    update(rt);
}

void modify(int rt,int l,int r){
    if(sum[rt]<=r-l+1) return;
    if(l==r){sum[rt]=sqrt(sum[rt]);return ;}
    if(a_l<=mid) modify(ls,l,mid);
    if(mid<a_r) modify(rs,mid+1,r);
    update(rt);
}

long long query(int rt,int l,int r){
    if(a_l<=l&&r<=a_r) return sum[rt];
    long long ans=0;
    if(a_l<=mid) ans+=query(ls,l,mid);
    if(mid<a_r) ans+=query(rs,mid+1,r);
    return ans;
}

int  main(){
  int num=0;
    while(scanf("%d",&n)!=EOF){
    printf("Case #%d:\n",++num);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
      build(1,1,n);
      scanf("%d",&m);
      for(int i=1;i<=m;i++){
          int ty;
          scanf("%d%d%d",&ty,&a_l,&a_r);
          if(a_l>a_r) swap(a_l,a_r);
          if(ty==0) modify(1,1,n);
          else printf("%lld\n",query(1,1,n));
      }
  }
}
View Code

 

上一篇:3分钟搞明白信用评分卡模型&模型验证


下一篇:[kuangbin带你飞]专题十二 基础DP1 B - Ignatius and the Princess IV