1. 程式人生 > >【CodeChef】September Challenge 2018 (Div. 1 + Div. 2) 題解

【CodeChef】September Challenge 2018 (Div. 1 + Div. 2) 題解

【比賽連結】

**【ANDSQR】**AND Square Subsegments

【思路要點】

  • 離線詢問,按左端點排序。
  • 列舉區間的左端點 l l ,區間 [
    l , i ] [l,i]
    a n
    d and
    和至多變化 O ( L o g
    V ) O(LogV)
    次,二分找到分界點,並找到其中是完全平方數的。
  • 每一段 a n d and 和相同的區間 [ l , i ] [l,i] 對答案的貢獻可以用一個關於右端點位置的一次函式來描述,用線段樹模擬即可。
  • 單組資料時間複雜度 O ( Q L o g N + N L o g N L o g V ) O(QLogN+NLogNLogV)

【程式碼】

#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

【思路要點】