BZOJ3211 花神游历各国 线段树

题意:给定一个数列,维护:1、区间求和  2、区间开根号

题解:

线段树,唯一的优化就是如果某区间的和为0和1,就不再向下进行更新。(注意long long)

另外动态开内存真的好慢- -,我的机子上3s(注意是s)才跑完一次,评测机T的不要不要的。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

typedef struct NODE{
    NODE *lchild,*rchild;
    int L,R;
    long long sum;
    bool lazy;
    NODE(){}
}*TREE;
TREE root;
int n,m;

void Pushup(TREE & node){
    node->sum=node->lchild->sum+node->rchild->sum;
    node->lazy=node->lchild->lazy&node->rchild->lazy;
}

void Build(TREE & root,int l,int r){
    root=new NODE;
    root->L=l,root->R=r,root->sum=root->lazy=0;

    if(l==r){
        scanf("%lld",&root->sum);
        if(root->sum==0 || root->sum==1) root->lazy=1;
        return;
    }

    int m=(l+r)>>1;
    Build(root->lchild,l,m);
    Build(root->rchild,m+1,r);

    Pushup(root);
}

long long Query(TREE & root,int l,int r){
    if(l<=root->L && r>=root->R) return root->sum;

    int m=(root->L+root->R)>>1;
    long long tmp=0;
    if(l<=m) tmp+=Query(root->lchild,l,r);
    if(r>=m+1) tmp+=Query(root->rchild,l,r);

    return tmp;
}

void Update(TREE & root,int l,int r){
    if(root->lazy) return;

    if(root->L==root->R){
        root->sum=(long long)sqrt(root->sum);
        if(root->sum==1 || root->sum==0) root->lazy=1;
        return;
    }

    int m=(root->L+root->R)>>1;
    if(l<=m) Update(root->lchild,l,r);
    if(r>m) Update(root->rchild,l,r);

    Pushup(root);
}

void Delete(TREE & root){
    if(root->L==root->R){
        delete root;
        return;
    }

    Delete(root->lchild);
    Delete(root->rchild);

    delete root;
}

void Visit(TREE & root){
    if(root->L==root->R){
        cout << root->sum << " ";
        return;
    }

    Visit(root->lchild);
    Visit(root->rchild);

    cout << root->sum << " ";
}

int main(){
    cin >> n;
    Build(root,1,n);

    cin >> m;
    int x,l,r;
    while(m--){
        cin >> x >> l >> r;
        l=min(l,r),r=max(l,r);

        if(x==1) cout << Query(root,l,r) << endl;
        if(x==2) Update(root,l,r);
    }

    Delete(root);

    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/WDZRMPCBIT/p/6477132.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值