• [Codevs] 4919 线段树练习4


    4919 线段树练习4

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 黄金 Gold
     
     
    题目描述 Description

    给你N个数,有两种操作

    1:给区间[a,b]内的所有数都增加X

    2:询问区间[a,b]能被7整除的个数

     
    输入描述 Input Description

    第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,表示操作的个数. 接下来Q行每行若干个整数。如果第一个数是add,后接3个正整数a,b,X,表示在区间[a,b]内每个数增加X,如果是count,表示统计区间[a,b]能被7整除的个数

     
    输出描述 Output Description

    对于每个询问输出一行一个答案

     
    样例输入 Sample Input   
    3 
    2 3 4
    6
    count 1 3
    count 1 2
    add 1 3 2
    count 1 3
    add 1 3 3
    count 1 3
    样例输出 Sample Output

    0

    0

    0

    1

     
    数据范围及提示 Data Size & Hint

    10%:1<N<=10,1<Q<=10

    30%:1<N<=10000,1<Q<=10000

    100%:1<N<=100000,1<Q<=100000

    分析 Analysis

    分块!

    相比线段树分块真的写起来很方便啊qwq

    每个块保存块内关于 7 的剩余系的元素数量

    (就是%7以后 0~6 的数量啦)

    关键是add 操作,真恶心

    用以前线段树的那套修改方案,最多过3个点

    看了看TJM的方案:

    每次整块增值时拉低bdd(负责保存历经修改以后整除 7 的数字到底是哪一个)

    查询时计数 mod[ block[ i ] ][ bdd[ i ] ]

    代码 Code 

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #define maxn 1000000
     5 using namespace std;
     6 
     7 char str[maxn/100];
     8 int block[maxn],mod[maxn][10],size,arr[maxn],add[maxn],bdd[maxn],n,m;
     9 
    10 void modify(){
    11     int a,b,c;
    12     scanf("%d%d%d",&a,&b,&c);
    13     a--,b--,c %= 7;
    14     if(!c) return;
    15     
    16     if(block[a] == block[b]){
    17         for(int i = a;i <= b;i++){
    18             mod[block[i]][arr[i]]--;
    19             arr[i] = (arr[i]+c)%7;
    20             mod[block[i]][arr[i]]++;
    21         }
    22     }else{
    23         
    24         for(int i = a;i <= block[a]*size-1;i++)
    25             mod[block[i]][arr[i]]--,
    26             arr[i] = (arr[i]+c)%7,
    27             mod[block[i]][arr[i]]++;
    28         for(int i = (block[b]-1)*size;i <= b;i++)
    29             mod[block[i]][arr[i]]--,
    30             arr[i] = (arr[i]+c)%7,
    31             mod[block[i]][arr[i]]++;
    32         for(int i = block[a]+1;i < block[b];i++)
    33             add[i] = (add[i]+c)%7,
    34             bdd[i] = (bdd[i]-c+7)%7;
    35             
    36     }
    37 }
    38 
    39 void count(){
    40     int a,b;
    41     scanf("%d%d",&a,&b);
    42     a--,b--;
    43     int ans = 0;
    44     
    45     if(block[a] == block[b]){
    46         for(int i = a;i <= b;i++)
    47             ans += ((arr[i]+add[block[i]])%7)?0:1;
    48     }else{
    49         
    50         for(int i = a;i <= block[a]*size-1;i++)
    51             ans += ((arr[i]+add[block[i]])%7)?0:1;
    52         for(int i = (block[b]-1)*size;i <= b;i++)
    53             ans += ((arr[i]+add[block[i]])%7)?0:1;
    54         for(int i = block[a]+1;i < block[b];i++)
    55             ans += mod[i][bdd[i]];
    56         
    57     }
    58     
    59     printf("%d
    ",ans);
    60 }
    61 
    62 void show(){
    63     for(int i = 0;i < n;i++){
    64         printf("%d ",arr[i]+add[block[i]]);
    65     }cout << endl;
    66 }
    67 
    68 int main(){
    69     scanf("%d",&n);
    70     size = (int)sqrt(n)+1;
    71     for(int i = 0;i < n;i++) block[i] = i/size+1;
    72 //    for(int i = 0;i < n;i++) printf("#%d: block %d
    ",i,block[i]);
    73     for(int i = 0;i < n;i++){
    74         scanf("%d",&arr[i]);
    75         arr[i] %= 7;
    76         mod[block[i]][arr[i]]++;
    77     }
    78 //    show();
    79     scanf("%d",&m);
    80     for(int i = 0;i < m;i++){
    81         scanf("%s",str);
    82         if(str[0] == 'a') modify();
    83         else count();
    84 //        show();
    85     }
    86     
    87     return 0;
    88 }
    我不想退役qwq
    转载请注明出处 -- 如有意见欢迎评论
  • 相关阅读:
    python 2
    Python 1 practice
    python 1
    Python多线程_笔记
    背景自适应不会随浏览器界面放大速效而改变
    平行四边形定理
    动态规划3(区间+树形)
    素数快速生成
    设CPU共有16根地址线,8根数据线,,,
    贪心+huffman编码+模拟退火+分治
  • 原文地址:https://www.cnblogs.com/Chorolop/p/7521235.html
Copyright © 2020-2023  润新知