P4145 上帝造题的七分钟 2 / 花神游历各国(线段树+区间修改+维护区间求和区间最大值)

题目传送门

题意

给定长度为n的整数序列,m次操作,操作如下:[k l r]
k=0 表示给[l,r]中的每个数开平方(向下取整)
k=1 表示询问[l,r]中的各个数的和。

输入格式

第一行一个整数 n,代表数列中数的个数。
第二行 n 个正整数,表示初始状态下数列中的数。
第三行一个整数 m,表示有 m 次操作。
接下来 m 行每行三个整数 k l r。
PS:数据中有可能 l>r,所以遇到这种情况请交换 l 和 r。

输出格式

对于询问操作,每行输出一个回答。

样例

input

10
1 2 3 4 5 6 7 8 9 10
5
0 1 10
1 1 10
1 1 5
0 5 8
1 4 8

output

19
7
6

思路

注意关键点是每次操作是开平方,1e12的数最多开6次平方就会变成1,所以暴力即可,如果对于当前区间中的最大值==1,那么我们就没必要继续开平方了。

code

#include <bits/stdc++.h>
using  namespace  std;

typedef long long ll;
typedef unsigned long long ull;
//#pragma GCC optimize(3)
#define pb push_back
#define is insert
#define PII pair<int,int>
#define show(x) cerr<<#x<<" : "<<x<<endl;
//mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count());
//ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);}

const int INF=0x3f3f3f3f;//2147483647;
const int N=1e5+50,M=1e5+50;
const ll mod=998244353;

ll a[N];
struct node {
    int l,r;
    ll sum,maxn;
}tr[N<<2];

void pushup(node &u,node &l,node &r){
    u.sum=l.sum+r.sum;
    u.maxn=max(l.maxn,r.maxn);
}
void pushup(int u){
    pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}

void build(int u,int l,int r){
    tr[u].l=l,tr[u].r=r;
    if(l==r){
        tr[u].maxn=a[l];
        tr[u].sum=a[l];
        return ;
    }
    int mid=l+r>>1;
    build(u<<1,l,mid);
    build(u<<1|1,mid+1,r);
    pushup(u);
}

node query(int u,int l,int r){
    if(l<=tr[u].l&&tr[u].r<=r){
        return tr[u];
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(r<=mid){
        return query(u<<1,l,r);
    }
    else if(l>mid){
        return query(u<<1|1,l,r);
    }
    else {
        node left=query(u<<1,l,r);
        node right=query(u<<1|1,l,r);
        node res;
        pushup(res,left,right);
        return res;
    }
}

void modify(int u,int l,int r){
    if(tr[u].l==tr[u].r){
        tr[u].maxn=sqrt(tr[u].maxn);
        tr[u].sum= sqrt(tr[u].sum);
        return ;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(l<=mid){
        if(tr[u<<1].maxn>1)modify(u<<1,l,r);
    }
    if(r>mid){
        if(tr[u<<1|1].maxn>1)modify(u<<1|1,l,r);
    }
    pushup(u);
}
int n,m;
void solve() {
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    build(1,1,n);
    cin>>m;
    while(m--){
        int op,l,r;cin>>op>>l>>r;
        if(l>r)swap(l,r);
        if(op==0){
            modify(1,l,r);
        }
        else {
            cout<<query(1,l,r).sum<<"\n";
        }
//        for(int i=1;i<=n;i++){
//            cout<<query(1,i,i).sum<<" ";
//        }cout<<endl;
    }
}

signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int __=1;//cin>>__;
    while(__--){
        solve();
    }
    return 0;
}

总结

太久没写线段树了,区间修改都能写错,哭哭。

posted @ 2022-03-30 19:59  illume  阅读(31)  评论(0编辑  收藏  举报