BZOJ 3787: Gty的文艺妹子序列 [分块 树状数组!]

传送门

题意:单点修改,询问区间内逆序对数,强制在线


看到加了!就说明花了不少时间....

如果和上题一样预处理信息,用$f[i][j]$表示块i到j的逆序对数

强行修改的话,每个修改最多会修改$(\frac{N}{S})^2$个信息,可以通过$S=N^{\frac{2}{3}}$达到$O(N^{\frac{5}{3}})$

但是我们可以更快

令$S=\sqrt{N}$

如果我们用$f[i][j]$表示一个块i中元素与一个块j中元素组成的逆序对数,一次修改就只会修改$\sqrt{N}$个信息啦

询问的时候,第二维套上一个树上数组,复杂度只是加上一个$log$而已

$s[i][j]$表示前i块中j出现次数,同理

 

我在哪里出问题了呢?$f$预处理错了,没有按照上面的意义来预处理,唉~

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=5e4+5, M=300;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return x*f;
}

int n, a[N], Q, l, r, op, p, v, col;
struct meow{int l,r;} b[M];
int block, m, pos[N];
inline void ini(){
    block=sqrt(n); m=(n-1)/block+1;
    for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
    for(int i=1;i<=m;i++) b[i].l=(i-1)*block+1, b[i].r=i*block;
    b[m].r=n;
}

struct BIT1{
    int c[M], n;
    inline void add(int p,int v) {for(;p<=n;p+=(p&-p)) c[p]+=v;}
    inline int sum(int p) {int re=0; for(;p;p-=(p&-p)) re+=c[p]; return re;}
    inline int que(int l,int r) {return sum(r) - sum(l-1);}
};
struct BIT2{
    int c[N], n;
    inline void add(int p,int v) {for(;p<=n;p+=(p&-p)) c[p]+=v;}
    inline int sum(int p) {int re=0; for(;p;p-=(p&-p)) re+=c[p]; return re;}
    inline int que(int l,int r) {return sum(r) - sum(l-1);}
};

struct Block{
    BIT1 f[M]; BIT2 s[M], C;
    void ini(){
        for(int i=1;i<=m;i++) f[i].n=m, s[i].n=col;
        C.n=col;
    }

    void Set(int x){ 
        for(int i=b[x].l; i<=b[x].r; i++) 
            f[x].add(x, C.que(a[i]+1, col) ), C.add(a[i], 1);
        for(int t=x+1; t<=m; t++)
            for(int i=b[t].l; i<=b[t].r; i++) f[x].add(t, C.que(a[i]+1, col) );
        
        for(int i=b[x].l; i<=b[x].r; i++) C.add(a[i], -1);

        //for(int i=1; i<=col; i++) s[x].add(i, s[x-1].que(i, i) );
        for(int i=1; i<=col; i++) s[x].c[i]= s[x-1].c[i];
        for(int i=b[x].l; i<=b[x].r; i++) s[x].add(a[i], 1);
    }

    inline int cal(int x,int y,int l,int r) {return s[y].que(l, r) - s[x-1].que(l, r);}

    int Que(int l, int r){ //printf("Que %d %d\n",l,r);
        int pl=pos[l], pr=pos[r];
        int ans=0;
        if(pl==pr){
            for(int i=l; i<=r; i++) ans+= C.que(a[i]+1, col), C.add(a[i], 1);
            for(int i=l; i<=r; i++) C.add(a[i], -1);
        }else{
            for(int x=pl+1; x<pr; x++) ans+= f[x].que(x, pr-1);// printf("f %d %d %d\n",x,pr-1,f[x].que(x, pr-1));
            //for(int i=1;i<=m;i++) printf("lalala %d %d\n",i,f[i].que(i, i+1) );

            //printf("ans %d\n",ans);

            for(int i=b[pr].l; i<=r; i++) 
                ans += C.que(a[i]+1, col) + cal(pl+1, pr-1, a[i]+1, col), C.add(a[i], 1);
                    //printf("hiaaa %d %d  %d %d\n",pr-1, pl, s[pr-1].que(a[i]+1, col) , s[pl].que(a[i]+1, col));
            //printf("ans %d\n",ans);
            for(int i=b[pl].r; i>=l; i--) 
                ans+= C.sum(a[i]-1) + cal(pl+1, pr-1, 1, a[i]-1), C.add(a[i], 1);
            for(int i=b[pr].l; i<=r; i++) C.add(a[i], -1);
            for(int i=l; i<=b[pl].r; i++) C.add(a[i], -1);
        }
        return ans;
    }

    void Cha(int p, int v){ //printf("Cha %d %d\n",p,v);
        int x=pos[p]; 
        f[x].add(x, -f[x].que(x, x));
        int _=a[p]; a[p]=v;
        for(int i=b[x].l; i<=b[x].r; i++) f[x].add(x, C.que(a[i]+1, col) ), C.add(a[i], 1);
        for(int i=b[x].l; i<=b[x].r; i++) C.add(a[i], -1);

        for(int t=x+1; t<=m; t++) 
            f[x].add(t, -cal(t, t, 1, _-1) ), f[x].add(t, cal(t, t, 1, v-1) );
        for(int t=1; t<x; t++)
            f[t].add(x, -cal(t, t, _+1, col) ), f[t].add(x, cal(t, t, v+1, col) );

        for(int t=x; t<=m; t++) s[t].add(_, -1), s[t].add(v, 1);
    }
}B;

int candy;
inline void debug() {
//    printf("a ");for(int i=1;i<=n;i++) printf("%d ",a[i]); puts("");
}
int main(){
    freopen("in","r",stdin);
    n=read(); col=n;
    for(int i=1;i<=n;i++) a[i]=read();

    ini();
    B.ini();
    for(int i=1;i<=m;i++) B.Set(i);
    //for(int i=1;i<=n;i++) printf("%d ",pos[i]);puts("");
    
    Q=read(); int lastans=0;
//candy=1;
    while(Q--){
        debug();
        op=read();
        if(op==0){
            if(candy) l=read(), r=read();
            else l=read()^lastans, r=read()^lastans;
            lastans=B.Que(l, r); printf("%d\n",lastans);
        }else{
            if(candy) p=read(), v=read();
            else p=read()^lastans, v=read()^lastans;
            B.Cha(p, v);
        }
    }
}

 

posted @ 2017-03-19 16:37  Candy?  阅读(391)  评论(0编辑  收藏  举报