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); } } }
Copyright:http://www.cnblogs.com/candy99/