codevs2492 上帝造题的七分钟 2

来源:互联网 发布:应用程序的端口号干什 编辑:程序博客网 时间:2024/04/30 06:12
2492 上帝造题的七分钟 2

题目描述 Description

  XLk觉得《上帝造题的七分钟》不太过瘾,于是有了第二部。

  "第一分钟,X说,要有数列,于是便给定了一个正整数数列。
  第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作。
  第三分钟,k说,要能查询,于是便有了求一段数的和的操作。
  第四分钟,彩虹喵说,要是noip难度,于是便有了数据范围。
  第五分钟,诗人说,要有韵律,于是便有了时间限制和内存限制。
  第六分钟,和雪说,要省点事,于是便有了保证运算过程中及最终结果均不超过64位有符号整数类型的表示范围的限制。
  第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。"
  ——《上帝造题的七分钟·第二部》
  所以这个神圣的任务就交给你了。

输入描述 Input Description

  第一行一个整数n,代表数列中数的个数。
  第二行n个正整数,表示初始状态下数列中的数。
  第三行一个整数m,表示有m次操作。
  接下来m行每行三个整数k,l,r,k=0表示给[l,r]中的每个数开平方(下取整),k=1表示询问[l,r]中各个数的和。
  UPD:注意数据中有可能l>r,所以遇到这种情况请交换l和r。

输出描述 Output Description

  对于询问操作,每行输出一个回答。

样例输入 Sample Input

10
1 2 3 4 5 6 7 8 9 10
5
0 1 10
1 1 10
1 1 5
0 5 8
1 4 8

样例输出 Sample Output

19
7
6

数据范围及提示 Data Size & Hint

  对于30%的数据,1<=n,m<=1000,数列中的数不超过32767。
  对于100%的数据,1<=n,m<=100000,1<=l,r<=n,数列中的数大于0,且不超过1e12。
  注意l有可能大于r,遇到这种情况请交换l,r。



来源:Nescafe 20

 

 

【思路】

      区间查询+打标记。

  一个关键的思想就是一个数被反复开方并向下取整最终会变为1,如果一个数变成1就不需要对它操作了。

  对于区间开方操作,对于区间中的每一个点都进行操作如果为1则下次不再操作。

  实现1:

         BIT+“并查集”。

【代码1】

 

 1 //341ms 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 7 using namespace std; 8  9 typedef long long LL;10 const int maxn = 200000+10;11 12 LL a[maxn],p[maxn];13 int n,m;14 15 LL read() {16     char c=getchar();17     while(!isdigit(c)) c=getchar();18     LL x=0;19     while(isdigit(c)) {20         x=x*10+c-'0';21         c=getchar();22     }23     return x;24 }25 26 LL c[maxn];27 int lowbit(int x) { return x&(-x); }28 LL Sum(LL x) {29     LL res=0;30     while(x>0) {31         res += c[x];32         x-=lowbit(x);33     }34     return res;35 }36 void Add(int x,LL d) {37     while(x<=n) {38         c[x] += d;39         x += lowbit(x);40     }41 }42 int find(int x) {43     return x==p[x]?x:p[x]=find(p[x]);44 }45 46 int main() {47     n=read();48     FOR(i,1,n) a[i]=read(),Add(i,a[i]);49     FOR(i,1,n+1) p[i]=i;                //n+1为哨兵 50     m=read();51     LL u,v,w;52     FOR(i,1,m) {53         w=read(),u=read(),v=read();54         if(u>v) swap(u,v);55         56         if(w)57             printf("%lld\n",Sum(v)-Sum(u-1));58         else 59         {60             for(int j=find(u);j<=v;j=find(j+1)) {61                 LL s=sqrt(a[j]);62                 Add(j,s-a[j]);63                 a[j]=s;64                 if(s==1) {65                     p[j]=j+1;66                     if(j==v) break;67                 }68             }69         }70     }71     return 0;72 }
View Code

 

  实现2:

         线段树+结点标记

【代码2】

 

 1 //399ms 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 7 using namespace std; 8  9 typedef long long LL;10 const int maxn = 500000+10;11 12 LL a[maxn],p[maxn];13 int n,m;14 15 LL read() {16     char c=getchar();17     while(!isdigit(c)) c=getchar();18     LL x=0;19     while(isdigit(c)) {20         x=x*10+c-'0';21         c=getchar();22     }23     return x;24 }25 26 LL sumv[maxn];27 bool f[maxn];28 void build(int u,int L,int R) {29     int lc=u*2,rc=u*2+1;30     if(L==R) {31         sumv[u]=a[L];32     }33     else {34         int M=L+(R-L)/2;35         build(lc,L,M);36         build(rc,M+1,R);37         sumv[u]=sumv[lc]+sumv[rc];38     }39 }40 int ya,yb;41 void update(int u,int L,int R) {42     int lc=u*2,rc=u*2+1;43     if(f[u]) return ;44     if(L==R) {45         sumv[u]=sqrt(sumv[u]);46         if(sumv[u]==1) f[u]=1;47     }48     else {49         int M=L+(R-L)/2;50         if(ya<=M) update(lc,L,M);51         if(M<yb)  update(rc,M+1,R);52         53         sumv[u]=sumv[lc]+sumv[rc];54         f[u]=f[lc]&&f[rc];55     }56 }57 LL query(int u,int L,int R) {58     int lc=u*2,rc=u*2+1;59     if(ya<=L && R<=yb) {60         return sumv[u];61     }62     else {63         int M=L+(R-L)/2;64         LL res=0;65         if(ya<=M) res+=query(lc,L,M);66          if(M<yb)  res+=query(rc,M+1,R);67          return res;68     }69 }70 71 int main() {72     n=read();73     FOR(i,1,n) a[i]=read();74     build(1,1,n);75     m=read();76     int w;77     while(m--) {78         w=read(),ya=read(),yb=read();79         if(ya>yb) swap(ya,yb);80         if(w)    printf("%lld\n",query(1,1,n));81         else update(1,1,n);82     }83     return 0;84 }
View Code

 

0 0
原创粉丝点击