zoukankan      html  css  js  c++  java
  • [Codevs] 2492 上帝造题的七分钟2

    2492 上帝造题的七分钟 2

     时间限制: 1 s
     空间限制: 64000 KB
     题目等级 : 大师 Master
     
    题目描述 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

    分析 Analysis

    这道题被自己搞的无比复杂= =

    再次死在追求正解的道路上= =

    根据hzwer的方法:单点暴力修改,区间求和

    (也就区间求和是线段树特性,单点暴力= =)

    本来以为必爆,但是分析复杂度发现 --不会爆qwq

    所以其实 hzwer 的优化就加了一个:

    对于一段连续区间,如果都是1,显然没必要继续开方,直接跳过

    那么在线段树版本中,如果一个子树整个的都是1,那么修改的时候就可以直接跳过了

    ------------------------------------------------------------------------

    然而据说正解是 树状数组+并查集 ?

    不过其实我不应该纠结正解 --能做而且不会爆就好

    毕竟不知道死在正解上多少次了

    树状数组+并查集 => 单点修改+区间求和+小优化

    小优化即上文所说的跳过11111111111111...

    代码 Code

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #define LL long long
     5 #define mid (L+R)/2
     6 #define lc (rt<<1)
     7 #define rc (rt<<1|1)
     8 #define maxn 1000000
     9 using namespace std;
    10 
    11 struct node{
    12     LL sum,flag;
    13 }Tree[maxn*4];
    14 
    15 int n,m;LL a,b,c;
    16 
    17 void maintain(int rt){
    18     Tree[rt].sum = Tree[lc].sum + Tree[rc].sum;
    19     Tree[rt].flag = Tree[lc].flag&Tree[rc].flag;
    20 }
    21 
    22 void build(int rt,int L,int R){
    23     if(L == R){
    24         scanf("%lld",&Tree[rt].sum);
    25         if(Tree[rt].sum == 1 || Tree[rt].sum == 0) Tree[rt].flag = 1;
    26         else Tree[rt].flag = 0;
    27     }else{
    28         build(lc,L,mid);
    29         build(rc,mid+1,R);
    30         
    31         maintain(rt);
    32     }
    33 }
    34 
    35 void modify(int rt,int L,int R,int qL,int qR){
    36     
    37     if(Tree[rt].flag) return;
    38     
    39     if(L == R){
    40         Tree[rt].sum = (LL)sqrt(Tree[rt].sum);
    41         if(Tree[rt].sum == 1 || Tree[rt].sum == 0) Tree[rt].flag = 1;
    42     }else{
    43         
    44         if(qL <= mid) modify(lc,L,mid,qL,qR);
    45         if(qR > mid) modify(rc,mid+1,R,qL,qR);
    46         
    47         maintain(rt);
    48     }
    49 }
    50 
    51 LL query(int rt,int L,int R,int qL,int qR){
    52     
    53 //    if(Tree[rt].flag) return (R-L+1);
    54     
    55     if(qL <= L && R <= qR){
    56         return Tree[rt].sum;
    57     }else{
    58         LL ans = 0;
    59         if(qL <= mid) ans += query(lc,L,mid,qL,qR);
    60         if(qR > mid) ans += query(rc,mid+1,R,qL,qR);
    61         
    62         return ans;
    63     }
    64 }
    65 
    66 int main(){
    67     scanf("%d",&n);
    68     build(1,1,n);
    69     scanf("%d",&m);
    70     
    71     for(int i = 1;i <= m;i++){
    72         scanf("%lld%lld%lld",&a,&b,&c);
    73         if(b > c) swap(b,c);
    74         if(a) printf("%lld
    ",query(1,1,n,b,c));
    75         else modify(1,1,n,b,c);
    76     }
    77     
    78     return 0;
    79 }
    线段树 版本
     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #define maxn 1000000
     5 #define LL long long
     6 #define lowbit(x) (-x&x)
     7 using namespace std;
     8 
     9 LL Tree[maxn],n,m,a,b,c,cnt,arr[maxn];
    10 void add(LL pos,LL val){
    11     while(pos <= n){
    12         Tree[pos] += val;
    13         pos += lowbit(pos);
    14     }
    15 }LL sum(LL pos){
    16     LL ans = 0;
    17     if(!pos) return ans;
    18     while(pos > 0){
    19         ans += Tree[pos];
    20         pos -= lowbit(pos);
    21     }return ans;
    22 }
    23 
    24 LL pre[maxn];
    25 LL find(LL x){
    26     if(!pre[x]) return x;
    27     else{
    28         pre[x] = find(pre[x]);
    29         return pre[x];
    30     }
    31 }void unite(LL u,LL v){
    32     if(find(u)!=find(v)) pre[find(u)] = find(v);
    33 }
    34 
    35 int main(){
    36     scanf("%lld",&n);
    37     for(LL i = 1;i <= n;i++){
    38         scanf("%lld",&arr[i]);
    39         add(i,arr[i]);
    40 //        for(int i = 1;i <= n;i++){
    41 //            printf("%lld ",sum(i));
    42 //        }cout << endl;
    43     }
    44     
    45     scanf("%lld",&m);
    46     for(LL i = 1;i <= m;i++){
    47         scanf("%lld%lld%lld",&a,&b,&c);
    48         
    49         if(b > c) swap(b,c);
    50         if(a){
    51             printf("%lld
    ",sum(c)-sum(b-1));
    52         }else{
    53             for(LL j = find(b);j <= c;j = find(j+1)){
    54                 if(j == 0) break;
    55                 add(j,-arr[j]);
    56                 arr[j] = (LL)sqrt(arr[j]);
    57                 add(j,arr[j]);
    58                 if(arr[j] == 1) pre[j] = j+1;
    59             }
    60         }
    61     }
    62     
    63     return 0;
    64 }
    树状数组+并查集 版本
    转载请注明出处 -- 如有意见欢迎评论
  • 相关阅读:
    工作中用到知识点
    工作中遇到问题的解决办法
    透明度兼容性(ie8以上)
    js阻止浏览器默认行为
    js停止冒泡和阻止浏览器默认行为
    js添加事件通用方法
    jquery常用插件
    延迟加载、异步加载js
    JavaScript兼容性问题
    创建对象的一种方式&一种继承机制(代码实例)
  • 原文地址:https://www.cnblogs.com/Chorolop/p/7454927.html
Copyright © 2011-2022 走看看