SP2713 GSS4 - Can you answer these queries IV
「题意」: n 个数,和在10^18 范围内。n<=1e5
现在有「两种」操作
0 x y
把区间[x,y] 内的每个数开方,下取整
1 x y
询问区间[x,y] 的每个数的和
和平常的线段树一样,只不过多了一个开方,拿计算器算一下,发现1e18开了大概6次后就会变为1,以后在开方就没用了,所以可以直接跳过这个区间
具体来说,维护一个区间的最大值,在每次执行‘ 0 ' 操作时,单点修改,若发现此区间最大值<=1,则不进入此区间,这样可以降低许多复杂度.
Code:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define ll long long using namespace std; int n,m,T; ll a[100010]; struct Node{ int l,r;ll dat,sum; #define l(p) t[p].l #define r(p) t[p].r #define sum(p) t[p].sum }t[100010*4]; inline ll read(){ char c=getchar();ll x=0,flag=1; while(c<'0' || c>'9'){if(c=='-') flag=-1;c=getchar();} while(c>='0' && c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar(); return x*flag; } void build(int p,int l,int r){ t[p].l=l;t[p].r=r; if(l==r){t[p].dat=t[p].sum=a[l];return;} int mid=(l+r)>>1;build(p*2,l,mid);build(p*2+1,mid+1,r); t[p].dat=max(t[p*2].dat,t[p*2+1].dat);t[p].sum=t[p*2].sum+t[p*2+1].sum; } void change(int p,int l,int r){ if(l(p)==r(p)){t[p].dat=sqrt(t[p].dat);t[p].sum=t[p].dat;return;} int mid=(l(p)+r(p))>>1; if(l<=mid && t[p*2].dat>1) change(p*2,l,r); if(r>mid && t[p*2+1].dat>1) change(p*2+1,l,r); t[p].dat=max(t[p*2].dat,t[p*2+1].dat);t[p].sum=t[p*2].sum+t[p*2+1].sum; } ll ask(int p,int l,int r){ if(l<=l(p) && r>=r(p)) return sum(p); int mid=(l(p)+r(p))>>1;ll val=0; if(l<=mid) val+=ask(p*2,l,r);if(r>mid) val+=ask(p*2+1,l,r); return val; } int main(){ while(scanf("%d",&n) != EOF){ printf("Case #%d:\n",++T); memset(&t,0,sizeof(t)); for(int i=1;i<=n;i++) a[i]=read(); build(1,1,n);m=read(); while(m--){ int num,x,y;num=read();x=read();y=read(); if(!num) change(1,min(x,y),max(x,y)); else printf("%lld\n",ask(1,min(x,y),max(x,y))); } printf("\n"); } }