2013-team4/code/block-array
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
{{{
把数组分成sqrt{N}块,每块大小为sqrt{N},这样可以在O(sqrt{N})时间内处理一个查询或者修改操作
可以用来很快解决一些树套树的问题,一道例子:UVA 12345 Dynamic len(set(a[L:R]))
一个长度为N的序列A[],两种操作
1.修改某一个值A[x]
2.询问区间[l,r]中不相同数字的个数
解法:
处理数pre[]数组,pre[i]表示前一个与A[i]相同数的位置,用块状数组维护pre数组就好了。修改操作可以用set维护
}}}
{{{
#include <map>
#include <set>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int MAXN=50005;
const int SIZE=1000005;
struct node
{
int l, r, size;
};
set<int> pos1[SIZE], pos2[SIZE];
node blk[MAXN];
int pre[SIZE];
int A[MAXN], F[MAXN], B[MAXN], own[MAXN];
int N, Q, M, L, cnt;
inline void change(int x, int v)
{
int px=own[x]; F[x]=v;
memcpy(B+blk[px].l, F+blk[px].l, sizeof(int)*blk[px].size);
sort(B+blk[px].l, B+blk[px].r);
}
int main()
{
for (int i=0; i<SIZE; i++) pos1[i].clear(), pos2[i].clear();
memset(pre, -1, sizeof(pre));
scanf("%d%d", &N, &Q); L=sqrt(N)+1; M=0;
for (int i=0; i<N; i++)
{
own[i]=i/L;
scanf("%d", &A[i]); F[i]=pre[A[i]];
pos1[A[i]].insert(i); pos2[A[i]].insert(-i);
if (i%L==0)
{
blk[M].l=i; blk[M].r=min(N, i+L);
blk[M].size=blk[M].r-blk[M].l; M++;
}
pre[A[i]]=i;
}
memcpy(B, F, sizeof(F));
for (int i=0; i<M; i++) sort(B+blk[i].l, B+blk[i].r);
while (Q--)
{
char st[10];
int x, y, px, py, ret=0;
scanf("%s%d%d", st, &x, &y);
if (st[0]=='M')
{
if (A[x]==y) continue;
set<int>::iterator it1, it2;
int p1, p2;
it1=pos1[A[x]].upper_bound(x); it2=pos2[A[x]].upper_bound(-x);
if (it1!=pos1[A[x]].end())
{
p1=*it1;
if (it2==pos2[A[x]].end()) p2=-1;
else p2=-(*it2);
change(p1, p2);
}
pos1[A[x]].erase(x); pos2[A[x]].erase(-x);
pos1[y].insert(x); pos2[y].insert(-x);
it1=pos1[y].upper_bound(x); it2=pos2[y].upper_bound(-x);
if (it1!=pos1[y].end()) change(*it1, x);
if (it2==pos2[y].end()) p2=-1;
else p2=-(*it2);
change(x, p2);
A[x]=y;
}
else
{
y--; px=own[x], py=own[y];
if (px==py)
{
for (int i=x; i<=y; i++) ret+=(F[i]<x);
}
else
{
for (int i=x; i<blk[px].r; i++) ret+=(F[i]<x);
for (int i=blk[py].l; i<=y; i++) ret+=(F[i]<x);
for (int i=px+1; i<py; i++)
ret+=lower_bound(B+blk[i].l, B+blk[i].r, x)-(B+blk[i].l);
}
printf("%d\n", ret);
}
}
return 0;
}
}}}
把数组分成sqrt{N}块,每块大小为sqrt{N},这样可以在O(sqrt{N})时间内处理一个查询或者修改操作
可以用来很快解决一些树套树的问题,一道例子:UVA 12345 Dynamic len(set(a[L:R]))
一个长度为N的序列A[],两种操作
1.修改某一个值A[x]
2.询问区间[l,r]中不相同数字的个数
解法:
处理数pre[]数组,pre[i]表示前一个与A[i]相同数的位置,用块状数组维护pre数组就好了。修改操作可以用set维护
#include <map>
#include <set>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int MAXN=50005;
const int SIZE=1000005;
struct node
{
int l, r, size;
};
set<int> pos1[SIZE], pos2[SIZE];
node blk[MAXN];
int pre[SIZE];
int A[MAXN], F[MAXN], B[MAXN], own[MAXN];
int N, Q, M, L, cnt;
inline void change(int x, int v)
{
int px=own[x]; F[x]=v;
memcpy(B+blk[px].l, F+blk[px].l, sizeof(int)*blk[px].size);
sort(B+blk[px].l, B+blk[px].r);
}
int main()
{
for (int i=0; i<SIZE; i++) pos1[i].clear(), pos2[i].clear();
memset(pre, -1, sizeof(pre));
scanf("%d%d", &N, &Q); L=sqrt(N)+1; M=0;
for (int i=0; i<N; i++)
{
own[i]=i/L;
scanf("%d", &A[i]); F[i]=pre[A[i]];
pos1[A[i]].insert(i); pos2[A[i]].insert(-i);
if (i%L==0)
{
blk[M].l=i; blk[M].r=min(N, i+L);
blk[M].size=blk[M].r-blk[M].l; M++;
}
pre[A[i]]=i;
}
memcpy(B, F, sizeof(F));
for (int i=0; i<M; i++) sort(B+blk[i].l, B+blk[i].r);
while (Q--)
{
char st[10];
int x, y, px, py, ret=0;
scanf("%s%d%d", st, &x, &y);
if (st[0]=='M')
{
if (A[x]==y) continue;
set<int>::iterator it1, it2;
int p1, p2;
it1=pos1[A[x]].upper_bound(x); it2=pos2[A[x]].upper_bound(-x);
if (it1!=pos1[A[x]].end())
{
p1=*it1;
if (it2==pos2[A[x]].end()) p2=-1;
else p2=-(*it2);
change(p1, p2);
}
pos1[A[x]].erase(x); pos2[A[x]].erase(-x);
pos1[y].insert(x); pos2[y].insert(-x);
it1=pos1[y].upper_bound(x); it2=pos2[y].upper_bound(-x);
if (it1!=pos1[y].end()) change(*it1, x);
if (it2==pos2[y].end()) p2=-1;
else p2=-(*it2);
change(x, p2);
A[x]=y;
}
else
{
y--; px=own[x], py=own[y];
if (px==py)
{
for (int i=x; i<=y; i++) ret+=(F[i]<x);
}
else
{
for (int i=x; i<blk[px].r; i++) ret+=(F[i]<x);
for (int i=blk[py].l; i<=y; i++) ret+=(F[i]<x);
for (int i=px+1; i<py; i++)
ret+=lower_bound(B+blk[i].l, B+blk[i].r, x)-(B+blk[i].l);
}
printf("%d\n", ret);
}
}
return 0;
}