bzoj 3211: 花神游历各国
直接写题解吧。。。
题目这么长,其实就是2个操作:
1.询问L,R中的各个数之和
2.将L,R中的每个数x,将x修x1/2,向下取整。。
我们其实可以发现1000000000中的数修改不了几次就会变成1
那么直接暴力修改,若一段区间内的数全部<=1也就不用再改下去了。。
#include<stdio.h> #include<iostream> #include<algorithm> #include<math.h> using namespace std; #define p1 (p<<1) #define p2 (p<<1|1) const int N=100005; int n,m,i,p,x,y,a[N],add[N<<2]; long long ans,t[N<<2]; void build(int l,int r,int p) { if(l==r) { t[p]=a[l]; if(a[l]<=1) add[p]=1;else add[p]=0; return; } int mid=(l+r)>>1; build(l,mid,p1); build(mid+1,r,p2); t[p]=t[p1]+t[p2]; add[p]=add[p1]&add[p2]; } void update(int l,int r,int x,int y,int p) { if(add[p]) return; if(l==r) { t[p]=(int)(sqrt(t[p])); if(t[p]<=1) add[p]=1; return; } int mid=(l+r)>>1; if(x<=mid) update(l,mid,x,y,p1); if(y>mid) update(mid+1,r,x,y,p2); add[p]=add[p1]&add[p2]; t[p]=t[p1]+t[p2]; } void solve(int l,int r,int x,int y,int p) { if(x<=l&&r<=y) { ans+=t[p]; return; } int mid=(l+r)>>1; if(x<=mid) solve(l,mid,x,y,p1); if(y>mid) solve(mid+1,r,x,y,p2); } int main() { scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1); scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%d%d%d",&p,&x,&y); if(p==1) { ans=0; solve(1,n,x,y,1); printf("%lld\n",ans); } else update(1,n,x,y,1); } return 0; }
一念起,天涯咫尺; 一念灭,咫尺天涯。