「CODECHEF FNCS」Chef and Churu【樹狀數組+分塊】

題目鏈接

題意

  • 就是給你一個長度爲nn數組以及nn個區間[li,ri][l_i,r_i],然後f(i)f(i)定義爲區間[li,ri][l_i,r_i]的和,然後兩種操作,一個是單點改值,另一個是查詢i=lrf(i)\sum_{i=l}^{r}{f(i)}

題解

  • 分塊套路題,和BZOJ4765差不多,將nn個區間分塊,預處理出數組中的每一個數對每一個塊的影響個數,維護每個塊的f(i)f(i)總和,然後改值的時候對所有的n\sqrt n個塊暴力更新塊的f(i)f(i)總和,然後查詢的時候對於整塊O(1)O(1)得到答案,非整塊用樹狀數組暴力查詢
  • 注意可能爆long longlong\ long,可還行

複雜度

  • O(nnlogn)O(n\sqrt n \log n)

代碼

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int smaxn=400;
int n,q,l[maxn],r[maxn],opt,u,v,b[maxn];

namespace bit{
    unsigned long long s[maxn];
    int lowbit(int x) {return x&(-x);} 
    void add(int id,int val){
        for(int i=id;i<=n;i+=lowbit(i)){  //注意這裏的n,需要根據題目要求改
            s[i]+=val;
        }
    }
    unsigned long long query(int id){
        unsigned long long ans=0;
        for(int i=id;i>=1;i-=lowbit(i)){
            ans+=s[i];
        }
        return ans;
    }
    unsigned long long qsum(int l,int r){return query(r)-query(l-1);}
    void clear(){memset(s,0,sizeof(s));}
}
using namespace bit;

namespace blocking{
    int tot,belong[maxn],siz[smaxn],block;  //分塊基本數據
    unsigned long long sum[maxn];                //解題數據
    int a[maxn],f[maxn][smaxn],c[maxn];
    void init(int n) {
        block=(int)sqrt((double)n);
        tot=n%block?(n/block+1):(n/block);
        for(int i=1;i<=n;i++) belong[i]=(i-1)/block+1;
        for(int i=1;i<=tot;i++) siz[i]=(min(i*block,n)-(i-1)*block);

        for(int i=1;i<=tot;i++) {
            for(int j=1;j<=n;j++) c[j]=0;
            for(int j=block*(i-1)+1;j<=min(i*block,n);j++) c[l[j]]++,c[r[j]+1]--;
            for(int j=1;j<=n;j++) c[j]+=c[j-1],f[j][i]=c[j];
        }
    }
    void update(int id,int val) {
        add(id,val-a[id]);
        for(int i=1;i<=tot;i++) sum[i]+=1LL*f[id][i]*(val-a[id]);
        a[id]=val;
    }

    unsigned long long query(int u,int v) {
        unsigned long long ans=0;
        if(belong[v]-belong[u]<=1) {
            for(int i=u;i<=v;i++) ans+=qsum(l[i],r[i]);
            return ans;
        }
        for(int i=u;i<=belong[u]*block;i++) ans+=qsum(l[i],r[i]);
        for(int i=belong[u]+1;i<=belong[v]-1;i++) ans+=sum[i];
        for(int i=(belong[v]-1)*block+1;i<=v;i++) ans+=qsum(l[i],r[i]);
        return ans;
    }

    void debug() {
        printf("block= %d, tot= %d\n",block,tot);
        for(int i=1;i<=n;i++) printf("%d%c",belong[i],i==n?'\n':' ');
    }
}
using namespace blocking;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    for(int i=1;i<=n;i++) scanf("%d %d",&l[i],&r[i]);
    init(n);
    for(int i=1;i<=n;i++) update(i,b[i]);
    scanf("%d",&q);
    while(q--) {
        scanf("%d %d %d",&opt,&u,&v);
        if(opt==2) printf("%llu\n",query(u,v));
        else update(u,v);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章