1. 程式人生 > >CODECHEF Chef and Churus 解題報告

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(n\sqrt 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\n",query(l,r));
    }
    return 0;
}

2018.12.13