【CodeChef】September Challenge 2018 (Div. 1 + Div. 2) 題解
阿新 • • 發佈:2018-11-08
【比賽連結】
**【ANDSQR】**AND Square Subsegments
【思路要點】
- 離線詢問,按左端點排序。
- 列舉區間的左端點 ,區間 的 和至多變化 次,二分找到分界點,並找到其中是完全平方數的。
- 每一段 和相同的區間 對答案的貢獻可以用一個關於右端點位置的一次函式來描述,用線段樹模擬即可。
- 單組資料時間複雜度 。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const int MAXQ = 5e5 + 5; const int MAXLOG = 20; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct SegmentTree { struct Node { int lc, rc, self; long long add; } a[MAXN * 2]; int n, q, root, size; vector <int> home[MAXN]; long long ans[MAXQ]; int newnode() { size++; a[size].lc = a[size].rc = 0; a[size].add = a[size].self = 0; return size; } void build(int &root, int l, int r) { root = newnode(); if (l == r) return; int mid = (l + r) / 2; build(a[root].lc, l, mid); build(a[root].rc, mid + 1, r); } void init(int x, int y) { n = x, q = y; root = size = 0; build(root, 1, n); for (int i = 1; i <= n; i++) home[i].clear(); for (int i = 1; i <= q; i++) ans[i] = 0; } void pushdown(int root) { a[a[root].lc].add += a[root].add; a[a[root].rc].add += a[root].add; a[a[root].lc].self += a[root].self; a[a[root].rc].self += a[root].self; a[root].add = a[root].self = 0; } void addquery(int root, int l, int r, int pos, int from) { if (l == r) { home[pos].push_back(from); ans[from] -= a[root].add + 1ll * a[root].self * pos; return; } pushdown(root); int mid = (l + r) / 2; if (mid >= pos) addquery(a[root].lc, l, mid, pos, from); else addquery(a[root].rc, mid + 1, r, pos, from); } void addquery(int pos, int from) { addquery(root, 1, n, pos, from); } void add(int root, int l, int r, int ql, int qr, int val) { if (l == ql && r == qr) { a[root].add += val; return; } int mid = (l + r) / 2; if (mid >= ql) add(a[root].lc, l, mid, ql, min(mid, qr), val); if (mid + 1 <= qr) add(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, val); } void mns(int root, int l, int r, int ql, int qr, int val) { if (l == ql && r == qr) { a[root].add -= val; a[root].self++; return; } int mid = (l + r) / 2; if (mid >= ql) mns(a[root].lc, l, mid, ql, min(mid, qr), val); if (mid + 1 <= qr) mns(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, val); } void addvalue(int lft, int l, int r) { int len = r - l + 1; if (r + 1 <= n) add(root, 1, n, r + 1, n, len); mns(root, 1, n, l, r, l - 1); } void dfs(int root, int l, int r) { if (l == r) { for (unsigned i = 0; i < home[l].size(); i++) ans[home[l][i]] += a[root].add + 1ll * a[root].self * l; return; } pushdown(root); int mid = (l + r) / 2; dfs(a[root].lc, l, mid); dfs(a[root].rc, mid + 1, r); } void output() { dfs(root, 1, n); for (int i = 1; i <= q; i++) writeln(ans[i]); } } ST; int Log[MAXN], val[MAXN][MAXLOG]; vector <int> rp[MAXN], home[MAXN]; int query(int l, int r) { int tmp = Log[r - l + 1]; return val[l][tmp] & val[r - (1 << tmp) + 1][tmp]; } bool square(int x) { int tmp = sqrt(x) + 1e-8; return tmp * tmp == x; } int main() { int T; read(T); while (T--) { int n, q; read(n), read(q); ST.init(n, q); for (int i = 1; i <= n; i++) { read(val[i][0]); rp[i].clear(); home[i].clear(); Log[i] = Log[i - 1]; if ((1 << (Log[i] + 1)) == i) Log[i]++; } for (int p = 1; p < MAXLOG; p++) for (int i = 1, j = 1 + (1 << (p - 1)); j <= n; i++, j++) val[i][p] = val[i][p - 1] & val[j][p - 1]; for (int i = 1; i <= q; i++) { int x, y; read(x), read(y); rp[x].push_back(y); home[x].push_back(i); } for (int i = 1; i <= n; i++) { for (unsigned j = 0; j < rp[i].size(); j++) ST.addquery(rp[i][j], home[i][j]); for (int j = i, nxt; j <= n; j = nxt) { int l = j, r = n, now = query(i, j); while (l < r) { int mid = (l + r + 1) / 2; if (query(i, mid) == now) l = mid; else r = mid - 1; } if (square(now)) ST.addvalue(i, j, l); nxt = l + 1; } } ST.output(); } return 0; }
**【BSHUFFLE】**Bad Shuffle
【思路要點】
- 似乎有這麼個結論,令 。
- 那麼有