[bzoj-3211]花神游历各国 题解

题目传送门
题意解析:题目就是告诉你n个数,然后有m个询问,每次询问有两个操作,一个是把一段区间内的和输出,一个是把一段区间中的每个数取根号。


My opinion:看到这题就应该知道应该用数据结构维护,不过这个根号该怎么办呢?我们都知道,根号让一个数降下来只需要几次就好了,而根号1或者0都不会变的,我算了一下让10^9变成1或0只需要根号5次就好了,所以,我们可以每次暴力根号,如果一段区间已经全部变成了0或1就不需要更改。那么就是剩下用什么数据结构了,当然是线段树或者分块了,然而有dalao跟我说分块超时(我没有试过),所以就直接写线段树了。
总结:
1、建树。
2、每次暴力维护,查询依旧。
对,没了,就这么些。


代码:

#include
#include
#include
#include
#include
#include
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define Clear(a,x) memset(a,x,sizeof(a))
#define ll long long
#define INF 2000000000
#define eps 1e-8
#define LEFT root<<1
#define RIGHT root<<1|1
#define Left root<<1,l,mid
#define Right root<<1|1,mid+1,r
using namespace std;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:f,ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=100005;
ll sum[maxn<<2];
bool xyf[maxn<<2];
int a[maxn];
int n;
void up(int root){
    sum[root]=sum[LEFT]+sum[RIGHT];
    xyf[root]=xyf[LEFT]&xyf[RIGHT];
}
void build(int root,int l,int r){
    if (l==r){
        sum[root]=a[l];
        if (a[l]==0||a[l]==1) xyf[root]=1;
            else xyf[root]=0;
        return;
    }
    int mid=(l+r)>>1;
    build(Left);
    build(Right);
    up(root);
}
ll find(int root,int l,int r,int x,int y){
    if (l>y||x>r) return 0;
    if (l==x&&r==y) return sum[root];
    int mid=(l+r)>>1;
    if (y<=mid) return find(Left,x,y);
        else if (x>mid) return find(Right,x,y);
            else return find(Left,x,mid)+find(Right,mid+1,y);
}
void change(int root,int l,int r,int x,int y){
    if (l>y||x>r) return;
    if (l==x&&r==y&&xyf[root]) return;
    if (l==r){
        a[l]=floor(sqrt(a[l]));
        sum[root]=a[l];
        if (a[l]==0||a[l]==1) xyf[root]=1;
        return;
    }
    int mid=(l+r)>>1;
    if (y<=mid) change(Left,x,y);
        else if (x>mid) change(Right,x,y);
            else{
                change(Left,x,mid);
                change(Right,mid+1,y);
            }
    up(root);
}
int main(){
    n=read();
    rep(i,1,n) a[i]=read();
    build(1,1,n);
    int q=read();
    while (q--){
        int op=read(),l=read(),r=read();
        if (op==1) printf("%lld\n",find(1,1,n,l,r));
            else change(1,1,n,l,r);
    }
    return 0;
}

附上AC记录:
这里写图片描述

你可能感兴趣的:(bzoj,线段树)