zoukankan      html  css  js  c++  java
  • CODECHEF Chef and Churus 解题报告

    【CODECHEF】Chef and Churus

    Description

    有一个长度为(n)的数组(A),有(n)个函数,第(i)个函数的值为(sum_{j=l_i}^{r_i}A_j)

    有两种操作:

    ①修改(A_i)

    ②询问第(l)~(r)个函数值的和。


    Input

    First Line is the size of the array i.e. N
    Next Line contains N space separated numbers Ai denoting the array
    Next N line follows denoting Li and Ri for each functions.
    Next Line contains an integer Q , number of queries to follow.
    Next Q line follows , each line containing a query of Type 1 or Type 2.
    1 x y : denotes a type 1 query,where x and y are integers
    2 m n : denotes a type 2 query where m and n are integers

    Output

    For each query of type 2 , output as asked above.


    说明

    (1 ≤ N ≤ 10^5,1 ≤ A_i ≤ 10^9,1 ≤ L_i ≤ N,L_i ≤ R_i ≤ N,1 ≤ Q ≤ 10^5)
    (1 ≤ x ≤ N,1 ≤ y ≤ 10^9,1 ≤ m ≤ N,m ≤ n ≤ N)


    一开始想了个做法,大概是把询问放到线段树的节点上,线段树维护区间和,外面用树状数组维护询问前缀和,然后每次修改的时候暴力改修改一条链的线段树节点上对树状数组的贡献。写完了感觉复杂度有点不对,好像是三个(log)的,又好像可以卡,反正T掉了。

    然后正解分块的思路真是神仙%%

    (A)进行分块,块内维护快内前缀和,块外维护块的前缀和。这样我们单点修改可以(O(sqrt n))做,但是询问区间和居然是(O(1))的。

    然后对询问进行分块,每个块(i)维护一个(dev_{i,j})代表块(i)中所有函数覆盖了几个(j)这个位置,可以差分进行预处理,再维护一个(sum_i)表示这一整块的答案。然后我们发现修改的时候遍历一遍所有块就行了,复杂度是(O(sqrt n))

    询问的时候,整块直接用(sum),散块直接暴力查询区间就可以,复杂度(O(sqrt n))

    于是总复杂度是(O(nsqrt n))

    注意开ull


    Code:

    #include <cstdio>
    #include <cmath>
    #define ll unsigned long long
    const int N=100010;
    const int M=320;
    ll F[M],f[N],a[N],sum[M];
    int L[N],R[N],dev[M][N],Belong[N],ql[N],qr[N],T,num,n,m;
    ll ask(int l,int r)//询问区间的和
    {
        int lp=Belong[l],rp=Belong[r];
        if(lp==rp) return f[r]-(l==L[lp]?0:f[l-1]);
        return f[R[lp]]-(l==L[lp]?0:f[l-1])+F[rp-1]-F[lp]+f[r];
    }
    void modify(int x,ll d)
    {
        int pos=Belong[x];//改数组块
        for(int i=x;i<=R[pos];i++)
            f[i]+=d-a[x];
        for(int i=pos;i<=num;i++)
            F[i]+=d-a[x];
        for(int i=1;i<=num;i++)//改询问块
            sum[i]+=(d-a[x])*dev[i][x];
        a[x]=d;
    }
    ll query(int l,int r)
    {
        int lp=Belong[l],rp=Belong[r];
        ll ret=0;
        if(lp==rp)
        {
            for(int i=l;i<=r;i++)
                ret+=ask(ql[i],qr[i]);
        }
        else
        {
            for(int i=l;i<=R[lp];i++)
                ret+=ask(ql[i],qr[i]);
            for(int i=L[rp];i<=r;i++)
                ret+=ask(ql[i],qr[i]);
            for(int i=lp+1;i<rp;i++)
                ret+=sum[i];
        }
        return ret;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%llu",f+i),a[i]=f[i];
        T=sqrt(n)+1;
        for(num=1;num*T<=n;num++) L[num]=T*(num-1)+1,R[num]=T*num;--num;
        if(R[num]<n) L[num+1]=R[num]+1,R[++num]=n;
        for(int i=1;i<=num;i++)
        {
            Belong[L[i]]=i;
            for(int j=L[i]+1;j<=R[i];j++)
                f[j]+=f[j-1],Belong[j]=i;
            F[i]+=f[R[i]]+F[i-1];
        }
        for(int i=1;i<=n;i++) scanf("%d%d",ql+i,qr+i);
        for(int i=1;i<=num;i++)
        {
            for(int j=L[i];j<=R[i];j++)
                ++dev[i][ql[j]],--dev[i][qr[j]+1];
            for(int j=1;j<=n;j++)
                dev[i][j]+=dev[i][j-1],sum[i]+=1ll*dev[i][j]*a[j];
        }
        scanf("%d",&m);
        for(int op,l,r,i=1;i<=m;i++)
        {
            scanf("%d%d%d",&op,&l,&r);
            if(op==1) modify(l,r);
            else printf("%llu
    ",query(l,r));
        }
        return 0;
    }
    

    2018.12.13

  • 相关阅读:
    Git忽略提交规则
    vue-echarts, vue 图表数据处理; axios 跨域代理
    css 画图
    span 空标签 width 设置无效 解决办法
    css 属性备忘录
    js 操作数组的方法 split()
    js 取整,四舍五入 Math.ceil()
    js 强制类型转换 parseInt,parseFloat,number
    dom级别和对应事件级别;事件流
    mac 使用命令行向 github 提交代码
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10112742.html
Copyright © 2011-2022 走看看