P4145 上帝造題的七分鐘 2 / 花神遊歷各國(線段樹+區間修改+維護區間求和區間最大值)
阿新 • • 發佈:2022-03-30
題意
給定長度為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; }
總結
太久沒寫線段樹了,區間修改都能寫錯,哭哭。