# [BZOJ 3236] [Ahoi2013] 作业 && [BZOJ 3809] 【莫队（+分块）】

### 算法一：莫队

Paste一个BZOJ-3236的纯莫队代码：

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

char c; c = getchar();
while (c < '0' || c > '9') c = getchar();
Num = c - '0'; c = getchar();
while (c >= '0' && c <= '9') {
Num = Num * 10 + c - '0';
c = getchar();
}
}

const int MaxN = 100000 + 5, MaxM = 1000000 + 5;

int n, m, BlkSize;
int A[MaxN], Cnt[MaxN], T1[MaxN], T2[MaxN];

struct Query
{
int l, r, a, b, Pos, e, Ans1, Ans2;
Query() {}
Query(int x, int y, int p, int q, int o) {
l = x; r = y; a = p; b = q; Pos = o;
}
bool operator < (const Query &q) const {
if (e == q.e) return r < q.r;
return e < q.e;
}
} Q[MaxM];

inline bool Cmp(Query q1, Query q2) {
return q1.Pos < q2.Pos;
}

inline void Add1(int x, int Num) {
for (int i = x; i <= n; i += i & -i)
T1[i] += Num;
}
inline int Get1(int x) {
if (x == 0) return 0; //Notice!
int ret = 0;
for (int i = x; i; i -= i & -i)
ret += T1[i];
return ret;
}

inline void Add2(int x, int Num) {
for (int i = x; i <= n; i += i & -i)
T2[i] += Num;
}
inline int Get2(int x) {
if (x == 0) return 0; //Notice!
int ret = 0;
for (int i = x; i; i -= i & -i)
ret += T2[i];
return ret;
}

if (Cnt[x] == 0) Add2(x, 1);
++Cnt[x];
}
inline void Del_Num(int x) {
--Cnt[x];
if (Cnt[x] == 0) Add2(x, -1);
}

void Pull(int f, int x, int y) {
if (x == y) return;
if (f == 0)
if (x < y)
for (int i = x; i < y; ++i) Del_Num(A[i]);
else
for (int i = x - 1; i >= y; --i) Add_Num(A[i]);
else
if (x < y)
for (int i = x + 1; i <= y; ++i) Add_Num(A[i]);
else
for (int i = x; i > y; --i) Del_Num(A[i]);
}

int main()
{
BlkSize = (int)sqrt((double)n);
for (int i = 1; i <= n; ++i) Read(A[i]);
int l, r, a, b;
for (int i = 1; i <= m; ++i) {
Q[i] = Query(l, r, a, b, i);
Q[i].e = (l - 1) / BlkSize + 1;
}
sort(Q + 1, Q + m + 1);
memset(Cnt, 0, sizeof(Cnt));
memset(T1, 0, sizeof(T1));
memset(T2, 0, sizeof(T2));
for (int i = Q[1].l; i <= Q[1].r; ++i) Add_Num(A[i]);
Q[1].Ans1 = Get1(Q[1].b) - Get1(Q[1].a - 1);
Q[1].Ans2 = Get2(Q[1].b) - Get2(Q[1].a - 1);
for (int i = 2; i <= m; ++i) {
if (Q[i].r < Q[i - 1].l) {
Pull(0, Q[i - 1].l, Q[i].l);
Pull(1, Q[i - 1].r, Q[i].r);
}
else {
Pull(1, Q[i - 1].r, Q[i].r);
Pull(0, Q[i - 1].l, Q[i].l);
}
Q[i].Ans1 = Get1(Q[i].b) - Get1(Q[i].a - 1);
Q[i].Ans2 = Get2(Q[i].b) - Get2(Q[i].a - 1);
}
sort(Q + 1, Q + m + 1, Cmp);
for (int i = 1; i <= m; ++i) printf("%d %d\n", Q[i].Ans1, Q[i].Ans2);
return 0;
}


### 算法二：莫队+分块

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

char c; c = getchar();
while (c < '0' || c > '9') c = getchar();
Num = c - '0'; c = getchar();
while (c >= '0' && c <= '9') {
Num = Num * 10 + c - '0';
c = getchar();
}
}

const int MaxN = 100000 + 5, MaxM = 1000000 + 5, MaxBlk = 350 + 5;

int n, m, BlkSize, TotBlk;
int A[MaxN], Cnt[MaxN], T[MaxBlk], L[MaxBlk], R[MaxBlk], Ans[MaxM], Blk[MaxN];

struct Query
{
int l, r, Index, a, b;
Query() {}
Query(int f, int x, int y, int p, int q) {
Index = f; l = x; r = y; a = p; b = q;
}
bool operator < (const Query &b) const {
if (Blk[l] == Blk[b.l]) return r < b.r;
return Blk[l] < Blk[b.l];
}
} Q[MaxM];

if (Cnt[x] == 0) ++T[Blk[x]];
++Cnt[x];
}

inline void Del_Num(int x) {
--Cnt[x];
if (Cnt[x] == 0) --T[Blk[x]];
}

void Pull(int f, int x, int y) {
if (x == y) return;
if (f == 0) {
if (x < y) for (int i = x; i < y; ++i) Del_Num(A[i]);
else for (int i = x - 1; i >= y; --i) Add_Num(A[i]);
}
else {
if (x < y) for (int i = x + 1; i <= y; ++i) Add_Num(A[i]);
else for (int i = x; i > y; --i) Del_Num(A[i]);
}
}

int GetAns(int a, int b) {
int x, y, ret;
x = Blk[a]; if (L[x] != a) ++x;
y = Blk[b]; if (R[y] != b) --y;
ret = 0;
if (x > y) {
for (int i = a; i <= b; ++i)
if (Cnt[i] > 0) ++ret;
}
else {
for (int i = x; i <= y; ++i) ret += T[i];
for (int i = a; i < L[x]; ++i)
if (Cnt[i] > 0) ++ret;
for (int i = b; i > R[y]; --i)
if (Cnt[i] > 0) ++ret;
}
return ret;
}

int main()
{
for (int i = 1; i <= n; ++i) Read(A[i]);
BlkSize = (int)sqrt((double)n);
TotBlk = (n - 1) / BlkSize + 1;
for (int i = 1; i <= TotBlk; ++i) {
L[i] = (i - 1) * BlkSize + 1;
R[i] = i * BlkSize;
}
R[TotBlk] = n;
for (int i = 1; i <= n; ++i) Blk[i] = (i - 1) / BlkSize + 1;
int l, r, a, b;
for (int i = 1; i <= m; ++i) {
Q[i] = Query(i, l, r, a, b);
}
sort(Q + 1, Q + m + 1);
memset(Cnt, 0, sizeof(Cnt));
memset(T, 0, sizeof(T));
for (int i = Q[1].l; i <= Q[1].r; ++i) Add_Num(A[i]);
Ans[Q[1].Index] = GetAns(Q[1].a, Q[1].b);
for (int i = 2; i <= m; ++i) {
if (Q[i].r < Q[i - 1].l) {
Pull(0, Q[i - 1].l, Q[i].l);
Pull(1, Q[i - 1].r, Q[i].r);
}
else {
Pull(1, Q[i - 1].r, Q[i].r);
Pull(0, Q[i - 1].l, Q[i].l);
}
Ans[Q[i].Index] = GetAns(Q[i].a, Q[i].b);
}
for (int i = 1; i <= m; ++i) printf("%d\n", Ans[i]);
return 0;
}


posted @ 2015-01-24 18:53  JoeFan  阅读(338)  评论(0编辑  收藏  举报