[平方根]

来源:互联网 发布:windows经典主题 编辑:程序博客网 时间:2024/04/28 08:32

题面:
这里写图片描述
观察发现,一个数最多被开平方根6次,6次以后就只能为1,可以不去处理
于是可以用线段树进行区间修改:
若待修改线段与当前线段重合,且这个区间里只有1,就可以不往下处理
否则就需要递归到最底部,进行直接修改
根据前面所说,一个数最多被处理6次,复杂度为O(6*nlogn)=O(nlogn)

当然,也可以用另一种方法:并查集+树状数组
因为1是无用的,所以从l~r修改时可以跳过一连串的1,这里很适合用并查集来处理
至于树状数组是用来快速统计区间加和的,复杂度O(nlogn)

#include<cstdio>#include<cmath>#include<cstdlib>#include<cstring>#define LL long long#define lowbit(x) ((x)&-(x))const int maxn=100005;int n,q,times,fa[maxn];LL a[maxn],tre[maxn];inline LL red(){    LL tot=0;char ch=getchar();    while (ch<'0'||'9'<ch) {if (ch==EOF) exit(0);ch=getchar();}    while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=getchar();    return tot;}void ist(int i,LL x){    while (i<=n)     tre[i]+=x,     i+=lowbit(i);}LL qry(int i){    LL res(0);    while (i)     res+=tre[i],     i-=lowbit(i);    return res;}int getfa(int x){    if (fa[x]==x) return x;    return fa[x]=getfa(fa[x]);}void work(int x){    LL aa=sqrt(a[x]);    ist(x,aa-a[x]);a[x]=aa;    if (aa==1) fa[x]=fa[x+1];}int main(){    freopen("sqrt.in","r",stdin);    freopen("sqrt.out","w",stdout);    while (n=red()){        printf("Case #%d:\n",++times);        memset(tre,0,sizeof(tre));        for (int i=1;i<=n;i++){            a[i]=red();ist(i,a[i]);            if (a[i]==1) fa[i]=i+1;else fa[i]=i;        }fa[n+1]=n+1;        q=red();int l,r;        while (q--)         if (red()) l=red(),r=red(),printf("%lld\n",qry(r)-qry(l-1));else{            l=red(),r=red();            for (int i=getfa(l);i<=r;i=getfa(i+1)) work(i);         }        putchar(10);    }    return 0;}
1 0
原创粉丝点击