• [COGS 2264]魔法传输


    [COGS 2264]魔法传输

    题目

    自从看了《哈利波特》,小Y就十分渴望获得魔法值。于是他和一群向往魔法的孩子(当然这些孩子们都是不会魔法的)来到了哈利波特的家,大家坐成一排。哈利波特会不时的给大家传输魔法。

    哈利每次会选择一个区间,给这个区间里的孩子们传输魔法:最左边的孩子给一点,第二个给两点……哈利有时会突然问你某一个孩子已经有了多少魔法。

    INPUT

    第一行两个正整数 N,M,表示有 N 个孩子,哈利有 M 次操作。

    接下来 M 行,每行代表一个操作。第一个字符为 ci,若 ci=‘C’则此次操作为传送魔法操作,接下来会有两个整数Li,Ri,表示此次送魔法值的区间。若 ci=‘Q’则此次操作为询问操作,接下来一个整数xi,表示询问第xi个孩子当前的魔法值。

    OUTPUT

    对于每组询问输出一行,仅包含一个整数,表示答案对 1,000,000,007 取模(mod)的结果。

    SAMPLE

    INPUT

    3 4

    C 1 3

    Q 2

    C 2 3

    Q 2

    OUTPUT

    2

    3

    数据规模

    对于 30%的数据,N,M≤1,000;

    对于 100%的数据,N,M≤100,000。

    解题报告

    一道难得的好题= =

    实际上这道题除了想出思路,哪都很容易= =

    这道题的主要难度就在于如何更改上,等差数列更改让一些数据结构显得很吃力,但实则不然,我们完全可以用线段树来实现这个东西

    我们首先思考,在线段树中如何更新。

    我们发现,我们需要在一段区间更新一段以$1$为首项的等差数列,那么,我们假如只在区间的每一个点加$1$,效果会怎样?

    显然这时候如果单点求和是不行的,但如果我们求前缀和的话,我们就可以得到等差数列求和的效果了不是吗?

    所以,我们可以看出,这是一道在线段树上的差分题。

    我们只需要在区间中的每一个点都加上$1$,右端点右面一个点减去$r-l+1$就可以达到差分的目的,查询时只需要查询单点前缀和即可

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 inline int read(){
     6     int sum(0);
     7     char ch(getchar());
     8     for(;ch<'0'||ch>'9';ch=getchar());
     9     for(;ch>='0'&&ch<='9';sum=sum*10+(ch^48),ch=getchar());
    10     return sum;
    11 }
    12 typedef long long L;
    13 int n,m;
    14 L sum[400005],add[400005];
    15 const L mod=1000000007;
    16 inline void pushup(int i){
    17     sum[i]=(sum[i<<1]+sum[i<<1|1])%mod;
    18 }
    19 inline void pushdown(int i,int len){
    20     if(add[i]){
    21         add[i<<1]+=add[i];
    22         add[i<<1|1]+=add[i];
    23         sum[i<<1]+=add[i]*(len-(len>>1));
    24         sum[i<<1]%=mod;
    25         sum[i<<1|1]+=add[i]*(len>>1);
    26         sum[i<<1|1]%=mod;
    27         add[i]=0;
    28     }
    29 }
    30 inline void update(int ll,int rr,L w,int l,int r,int i){
    31     if(ll<=l&&r<=rr){
    32         add[i]+=w;
    33         sum[i]+=w*(L)(r-l+1);
    34         sum[i]%=mod;
    35         return;
    36     }
    37     pushdown(i,r-l+1);
    38     int mid((l+r)>>1);
    39     if(ll<=mid)
    40         update(ll,rr,w,l,mid,i<<1);
    41     if(mid<rr)
    42         update(ll,rr,w,mid+1,r,i<<1|1);
    43     pushup(i);
    44 }
    45 inline L query(int ll,int rr,int l,int r,int i){
    46     if(ll<=l&&r<=rr)
    47         return sum[i];
    48     pushdown(i,r-l+1);
    49     L ret(0);
    50     int mid((l+r)>>1);
    51     if(ll<=mid)
    52         ret=(ret+query(ll,rr,l,mid,i<<1))%mod;
    53     if(mid<rr)
    54         ret=(ret+query(ll,rr,mid+1,r,i<<1|1))%mod;
    55     return ret;
    56 }
    57 char op[2];
    58 inline int gg(){
    59     freopen("magics.in","r",stdin);
    60     freopen("magics.out","w",stdout);
    61     n=read(),m=read();
    62     while(m--){
    63         scanf("%s",op);
    64         if(op[0]=='Q'){
    65             int x(read());
    66             printf("%lld
    ",query(1,x,1,n,1)%mod);
    67         }
    68         else{
    69             int x(read()),y(read());
    70             update(x,y,1,1,n,1);
    71             update(y+1,y+1,-(y-x+1),1,n,1);
    72         }
    73     }
    74     return 0;
    75 }
    76 int K(gg());
    77 int main(){;}
    View Code
  • 相关阅读:
    IIS大量出现Connections_Refused的错误提示
    SQL分类汇总统计聚合查询
    PHP_保留两位小数并且四舍五入_保留两位小数并且不四舍五入
    忘记Ucenter创始人密码的最快速解决方法
    NetBeans无法使用编码GBK安全地打开该文件
    PHP连续输出字母AZ
    C# 和 Linux 时间戳转换
    php中使用header在下载时乱码问题解决
    PHP获取当前时间、时间戳的各种格式写法汇总[日期时间]
    一些PHP性能优化
  • 原文地址:https://www.cnblogs.com/hzoi-mafia/p/7358997.html
Copyright © 2020-2023  润新知