BZOJ 3211 花神游离各国 小清新线段树
花神游离各国
题目大意:给定长度为N的序列,支持区间开根,区间求和
样例
样例输入
题解:
平常的线段树维护标记非常麻烦
我们发现一个数多次开根后会是1或0,所以我们维护一个区间是否有需要修改的点,然后单点修改即可
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define MAXN 100005 #define ll long long using namespace std; ll n,m,like[4*MAXN]; struct node{ ll l,r,f,w,b; }tree[4*MAXN]; void down(ll k){ tree[k*2].w=tree[k*2+1].w=tree[k*2].f=tree[k*2+1].f=tree[k].f; tree[k].f=0; } void build(ll k,ll l,ll r){ tree[k].l=l,tree[k].r=r; if(l==r){ scanf("%lld",&like[k]); tree[k].w=tree[k].b=like[k]; return ; } ll mid=(l+r)>>1; build(k*2,l,mid); build(k*2+1,mid+1,r); tree[k].w=tree[k*2].w+tree[k*2+1].w; tree[k].b=max(tree[k*2].b,tree[k*2+1].b); } ll get_sum(ll k,ll x,ll y){ ll ans=0,mid=(tree[k].l+tree[k].r)>>1; if(tree[k].l>=x&&tree[k].r<=y) return tree[k].w; if(tree[k].f) down(k); if(x<=mid) ans+=get_sum(k*2,x,y); if(mid<y) ans+=get_sum(k*2+1,x,y); return ans; } void change(ll k,ll l,ll r){ if(tree[k].b<=1) return ; if(tree[k].l==tree[k].r&&tree[k].w>1){ tree[k].w=tree[k].f=(ll)sqrt(tree[k].w); tree[k].b=(ll)sqrt(tree[k].b); return ; } if(tree[k].f) down(k); ll mid=(tree[k].l+tree[k].r)>>1; if(l<=mid) change(k*2,l,r); if(mid<r) change(k*2+1,l,r); tree[k].w=tree[k*2].w+tree[k*2+1].w; tree[k].b=max(tree[k*2].b,tree[k*2+1].b); } int main(){ scanf("%lld",&n); build(1,1,n); scanf("%lld",&m); for(ll i=1,opt,x,y;i<=m;i++){ scanf("%lld%lld%lld",&opt,&x,&y); if(opt==1) printf("%lld\n",get_sum(1,x,y)); if(opt==2) change(1,x,y); } return 0; }