洛谷 P4145 上帝造题的七分钟2 / 花神游历各国

传送门:洛谷 P4145 上帝造题的七分钟2 / 花神游历各国
题目描述:

将区间内的每个数开平方,并区间求和


算法分析:\(\sqrt{x}\) 向下取整,那么\(\forall x \in R\),在经过有限次开平方运算后,其结果一定为\(1\)。故只需将大于\(1\)的区间的数开平方即可,就能大大降低时间复杂度,然后在更新时只要递归修改即可(\(10^{12}\)至多需要6次修改),查询时区间查询。在这里用了两个数组:\(sum\)\(maxi\)\(sum\)存储和,\(maxi\)储存区间最大值。若区间最大值 \(>1\),则需修改。


#include<iostream>
#include<cstdio>
#include<cmath>
#define ls k<<1
#define rs k<<1 | 1
#define mid ((l+r)>>1)
#define G ch=getchar()
#define in(x) x=read()
#define S(x) x=(int)sqrt(x)
using namespace std;
const int maxN=100000;
typedef long long rd;
typedef long long ll;
inline rd read();
int n,m,l,r,op;
ll sum[4*maxN+1],maxi[4*maxN+1];
void update(int,int,int,int,int);
ll query(int,int,int,int,int);
void build(int,int,int),pushup(int);
int main()
{
    in(n); build(1,1,n); in(m);
    for(register int i=1;i<=m;i++)
    {
        in(op); in(l); in(r);
        if(l>r) swap(l,r);
        if(op==0) update(1,1,n,l,r);
        else printf("%lld\n",query(1,1,n,l,r));
    }
    return 0;
}
void pushup(int k)
{
    sum[k]=sum[ls]+sum[rs];
    maxi[k]=max(maxi[ls],maxi[rs]);
}
void update(int k,int l,int r,int ql,int qr)
{
    if(l==r) {S(sum[k]); S(maxi[k]); return;}
    if(ql<=mid && maxi[ls]>1) update(ls,l,mid,ql,qr);
    if(qr>mid && maxi[rs]>1) update(rs,mid+1,r,ql,qr);
    pushup(k);
}
ll query(int k,int l,int r,int ql,int qr)
{
    if(ql<=l && r<=qr) return sum[k];
    ll ans=0;
    if(ql<=mid) ans+=query(ls,l,mid,ql,qr);
    if(qr>mid) ans+=query(rs,mid+1,r,ql,qr);
    return ans;
}
void build(int k,int l,int r)
{
    if(l==r) {in(sum[k]); maxi[k]=sum[k]; return;}
    build(ls,l,mid); build(rs,mid+1,r);
    pushup(k);
}
inline rd read()
{
    char ch=getchar();
    rd num=0,f=1;
    while((ch<'0' || ch>'9') && ch!='-') G;
    if(ch=='-') {f=-1; G;}
    while(ch>='0' && ch<='9') {num=num*10+ch-'0'; G;}
    return num*f;
}
posted @ 2019-02-14 12:02  常青藤的花语  阅读(133)  评论(0编辑  收藏  举报

知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。