Description
Input
Output
每次x=1时,每行一个整数,表示这次旅行的开心度
Sample Input
4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
Sample Output
101
11
11
11
11
HINT
对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9
题解:可以发现一个数最多开log次根就会变成0或1.
然后一个数如果还没变成0或1,我们就暴力修改
如果已经变成0或1,我们就用并查集维护一下0,1块。
这样每个数只会被访问log次,
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#define N 100010
using namespace std;
long long t[N*4];
int a[N];
int n,m,l,r,fa[N],kind,tt;
inline int find(int x){if (x!=fa[x]) fa[x]=find(fa[x]);return fa[x];}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void change(int k,int l,int r,int p,long long v){
int mid=(l+r)>>1;
if (l==r){t[k]=a[p];return;}
if (p<=mid) change(k<<1,l,mid,p,v);
else change(k<<1|1,mid+1,r,p,v);
t[k]=t[k<<1]+t[k<<1|1];
}
inline long long query(int k,int l,int r,int ll,int rr){
int mid=(l+r)>>1;long long ans(0);
if (ll<=l&&r<=rr) return t[k];
if (ll<=mid) ans+=query(k<<1,l,mid,ll,rr);
if (mid<rr) ans+=query(k<<1|1,mid+1,r,ll,rr);
return ans;
}
int main(){
n=read();
for (int i=1;i<=n;i++) {a[i]=read();change(1,1,n,i,(long long)a[i]);}
for (int i=1;i<=n+1;i++) fa[i]=i;
m=read();
for (int i=1;i<=m;i++){
kind=read();l=read();r=read();if (l>r) swap(l,r);
if (kind==1) printf("%lld\n",query(1,1,n,l,r));
if (kind==2){
tt=find(l);
while (tt<=r){
a[tt]=sqrt(a[tt]);
change(1,1,n,tt,(long long)a[tt]);
if (a[tt]==1||a[tt]==0) fa[tt]=tt+1;
if (find(tt)!=tt) tt=find(tt);else tt++;
}
}
}
}