1. 程式人生 > 其它 >P4145 上帝造題的七分鐘 2 / 花神遊歷各國(線段樹+區間修改+維護區間求和區間最大值)

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;
}

總結

太久沒寫線段樹了,區間修改都能寫錯,哭哭。