BZOJ 2427 & 分块裸题
题意:
求区间内的众数,强制在线.
SOL:
推荐一个大神犇的blog,讲的还是很好的(主要我喜欢他的代码风格(逃:http://www.cnblogs.com/JoeFan/p/4248767.html
太裸没什么意思...虽然好些但码码也挺长的...
还是贴那个大神的代码天天看着代码打的会不会好看点>_<
#include <iostream> #include <cstdlib> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; inline void Read(int &Num) { 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 = 40000 + 5, MaxBlk = 200 + 5; int n, m, BlkSize, TotBlk; int A[MaxN], TL[MaxN], T[MaxN], Cnt[MaxN], L[MaxBlk], R[MaxBlk], First[MaxN], Last[MaxN]; int f[MaxBlk][MaxBlk], g[MaxBlk][MaxBlk]; struct ES { int Pos, Num, v; } E[MaxN]; inline bool Cmp_Num(ES e1, ES e2) { if (e1.Num == e2.Num) return e1.Pos < e2.Pos; return e1.Num < e2.Num; } inline bool Cmp_Pos(ES e1, ES e2) {return e1.Pos < e2.Pos;} int GetNum(int Num, int x, int y) { if (x > y || x > E[Last[Num]].Pos || y < E[First[Num]].Pos) return 0; int l, r, mid, p1, p2; l = First[Num]; r = Last[Num]; while (l <= r) { mid = (l + r) >> 1; if (E[mid].Pos >= x) { p1 = mid; r = mid - 1; } else l = mid + 1; } l = First[Num]; r = Last[Num]; while (l <= r) { mid = (l + r) >> 1; if (E[mid].Pos <= y) { p2 = mid; l = mid + 1; } else r = mid - 1; } return p2 - p1 + 1; } int main() { Read(n); Read(m); for (int i = 1; i <= n; ++i) { Read(E[i].Num); E[i].Pos = i; } sort(E + 1, E + n + 1, Cmp_Num); int v_Index = 0; for (int i = 1; i <= n; ++i) {//离散化 if (i == 1 || E[i].Num > E[i - 1].Num) ++v_Index; E[i].v = v_Index; TL[v_Index] = E[i].Num;//再映射回来 } sort(E + 1, E + n + 1, Cmp_Pos); for (int i = 1; i <= n; ++i) A[i] = E[i].v; sort(E + 1, E + n + 1, Cmp_Num); //三次排序感觉真是浪费啊... for (int i = 1; i <= n; ++i) { if (First[E[i].v] == 0) First[E[i].v] = i; Last[E[i].v] = 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 <= TotBlk; ++i) { for (int j = 1; j <= n; ++j) Cnt[j] = 0; f[i][i - 1] = 0; g[i][i - 1] = 0; for (int j = i; j <= TotBlk; ++j) { f[i][j] = f[i][j - 1]; g[i][j] = g[i][j - 1]; for (int k = L[j]; k <= R[j]; ++k) { ++Cnt[A[k]]; if (Cnt[A[k]] > f[i][j] || (Cnt[A[k]] == f[i][j] && A[k] < g[i][j])) { f[i][j] = Cnt[A[k]]; g[i][j] = A[k];//次数和数 } } } } memset(Cnt, 0, sizeof(Cnt)); for (int i = 1; i <= n; ++i) T[i] = -1; int l, r, x, y, Ct, Ans, Cu; Ans = 0; for (int i = 1; i <= m; ++i) { Read(l); Read(r); l = (l + Ans - 1) % n + 1; r = (r + Ans - 1) % n + 1;//强制在线 if (l > r) swap(l, r); x = (l - 1) / BlkSize + 1; if (l != L[x]) ++x; y = (r - 1) / BlkSize + 1; if (r != R[y]) --y; if (x > y) { Ct = 0; Ans = 0; for (int j = l; j <= r; ++j) { ++Cnt[A[j]]; if (Cnt[A[j]] > Ct || (Cnt[A[j]] == Ct && A[j] < Ans)) { Ct = Cnt[A[j]]; Ans = A[j]; } } for (int j = l; j <= r; ++j) --Cnt[A[j]]; } else { Ct = f[x][y]; Ans = g[x][y]; for (int j = l; j < L[x]; ++j) { ++Cnt[A[j]]; if (T[A[j]] == -1) T[A[j]] = GetNum(A[j], L[x], R[y]); Cu = Cnt[A[j]] + T[A[j]]; if (Cu > Ct || (Cu == Ct && A[j] < Ans)) { Ct = Cu; Ans = A[j]; } } for (int j = r; j > R[y]; --j) { ++Cnt[A[j]]; if (T[A[j]] == -1) T[A[j]] = GetNum(A[j], L[x], R[y]); Cu = Cnt[A[j]] + T[A[j]]; if (Cu > Ct || (Cu == Ct && A[j] < Ans)) { Ct = Cu; Ans = A[j]; } } for (int j = l; j < L[x]; ++j) {--Cnt[A[j]]; T[A[j]] = -1;} for (int j = r; j > R[y]; --j) {--Cnt[A[j]]; T[A[j]] = -1;} } Ans = TL[Ans]; printf("%d\n", Ans); } return 0; }
Sometimes it s the very people who no one imagines anything of. who do the things that no one can imagine.