分块

    xiaoxiao2021-03-25  124

    1、POJ 2104 K-th Number

    参考:《挑战程序设计竞赛》P186

    注意:

    1、各种边界问题

    2、块的大小要合适,比如书中的1000,块的大小为sqrt(n)会超时,因为在进行判断的时候复杂度是有差别的,分别为sqrt(n * logn和sqrt(n) * logn

    3、二分的时候试着不用判断而是循环100次,竟然WA了。。。

    #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <queue> #include <vector> #include <stack> #include <map> #include <set> #include <cmath> #include <cctype> #include <ctime> #include <cassert> using namespace std; #define REP(i, n) for (int i = 0; i < (n); ++i) #define eps 1e-9 typedef long long ll; typedef pair<int, int> pii; const int INF = 1e9; const int maxn = 1e5 + 10; int n, m, x, y, k, block, Left, Right; int a[maxn], a_t[maxn], a_sorted[maxn]; int judge(int num); int main() { #ifdef __AiR_H freopen("in.txt", "r", stdin); // freopen("out3.txt", "w", stdout); #endif // __AiR_H scanf("%d %d", &n, &m); block = 1000; int t = n / block; REP(i, n) { scanf("%d", &a[i]); a_t[i] = a[i]; a_sorted[i] = a[i]; } for (int i = 0; i < t * block; i += block) { sort(a + i, a + i + block); } sort(a_sorted, a_sorted + n); int low = -1, high = n - 1, mid; while (m--) { scanf("%d %d %d", &x, &y, &k); if ((x - 1) % block == 0) { Left = x - 1; } else { Left = ((x - 1) / block + 1) * block; } if (y % block == 0) { Right = y; } else { Right = (y / block) * block; } --x; --y; low = -1; high = n - 1; while (high - low > 1) { mid = low + (high - low) / 2; if (judge(a_sorted[mid])) { high = mid; } else { low = mid; } } printf("%d\n", a_sorted[high]); } #ifdef __AiR_H printf("Time used = %.2fs\n", (double)clock() / CLOCKS_PER_SEC); #endif // __AiR_H return 0; } int judge(int num) { int cnt = 0; if (Left >= Right - 1) { for (int i = x; i <= y; ++i) { if (a_t[i] <= num) { ++cnt; } } if (cnt >= k) { return 1; } return 0; } for (int i = x; i < Left; ++i) { if (a_t[i] <= num) { ++cnt; } } for (int i = Left; i < Right; i += block) { cnt += upper_bound(a + i, a + i + block, num) - (a + i); } for (int i = Right; i <= y; ++i) { if (a_t[i] <= num) { ++cnt; } } if (cnt >= k) { return 1; } return 0; }

    2、SPOJ - ADALIST

    借鉴了@tju-fishporridge大佬的代码,他是双端队列写的,比vector要慢好多。。。

    #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <queue> #include <vector> #include <stack> #include <map> #include <set> #include <cmath> #include <cctype> #include <ctime> #include <cassert> using namespace std; #define REP(i, n) for (int i = 0; i < (n); ++i) #define eps 1e-9 typedef long long ll; typedef pair<int, int> pii; const int INF = 0x7fffffff; const int maxn = 1e5 + 10; int N, Q, cmd, k, x, block; int a[maxn]; vector<int> v[1000]; int main() { #ifdef __AiR_H freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); #endif // __AiR_H scanf("%d %d", &N, &Q); REP(i, N) { scanf("%d", &a[i]); } block = sqrt(N + Q); REP(i, N) { v[i / block].push_back(a[i]); } while (Q--) { scanf("%d %d", &cmd, &k); if (cmd == 1) { --k; } int cur = 0; while (k > (int)v[cur].size()) { k -= v[cur++].size(); } if (cmd == 1) { scanf("%d", &x); v[cur].insert(v[cur].begin() + k, x); } else if (cmd == 2) { v[cur].erase(v[cur].begin() + k - 1); } else { printf("%d\n", v[cur][k - 1]); } } #ifdef __AiR_H printf("Time used = %.2fs\n", (double)clock() / CLOCKS_PER_SEC); #endif // __AiR_H return 0; }

    转载请注明原文地址: https://ju.6miu.com/read-19373.html

    最新回复(0)