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;
}
总结
太久没写线段树了,区间修改都能写错,哭哭。