码迷,mamicode.com
首页 > 其他好文 > 详细

CodeChef February Challenge 2018 Chef and odd queries (分块 + 主席树)

时间:2018-02-17 10:26:54      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:end   def   ++   log   ref   bit   题目   query   奇数   

题目链接  Chef and odd queries

题意  给定$n$个区间和$q$个询问,每个询问给定$m$个点,求这$n$个区间中有多少个包含了$m$个点中的奇数个。

 

分类操作。

对于$m >$ $\sqrt{n}$的询问直接一个前缀和依次枚举,时间复杂度$O(n)$,因为这样的询问不会超过$\sqrt{n}$个,

所以规定时间内可以通过。

 

对于$m <$ $\sqrt{n}$的询问,两两枚举这$m$个点,枚举的时间复杂度为$O(n)$

枚举的点对必满足这两个点之间(包括这两个点)点个数为奇数。

当枚举的点对为$(x_{i}, x_{j})$的时候,我们要查询左端点在$[x_{i-1}+1,x_{i}]$,右端点落在$[x_{j},x_{j+1}-1]$的区间个数。

对$x[]$建立主席树,$root[i]$维护的是坐标范围 $<= i$的这些点,那么对于每次查询可以在$O(logn)$的时间完成。

当然也可以通过离线在树状数组上询问。

时间复杂度$O(n^{\frac{3}{2}}logn)$

 

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

const int N = 1e5 + 10;
const int M = 5e6 + 10;

struct node{
	int l, r;
	void scan(){ scanf("%d%d", &l, &r);}
	friend bool operator < (const node &a, const node &b){
		return a.l == b.l ? a.r < b.r : a.l < b.l;
	}
} a[N];

int T, split, tot, ans, n, m, y;
int x[N], root[N], s[N], f[M], ls[M], rs[M];

int ins(int x, int l, int r, int val){
	int u = ++tot;
	f[u] = f[x] + 1;
	ls[u] = ls[x];
	rs[u] = rs[x];
	if (l == r) return u;
	int mid = (l + r) >> 1;
	if (val <= mid) ls[u] = ins(ls[x], l, mid, val);
	else rs[u] = ins(rs[x], mid + 1, r, val);
	return u;
}

int query(int x, int L, int R, int l, int r){
	if (l <= L && R <= r) return f[x];
	int ret = 0;
	int mid = (L + R) >> 1;
	if (l <= mid) ret += query(ls[x], L, mid, l, r);
	if (r  > mid) ret += query(rs[x], mid + 1, R, l, r);
	return ret;
}

int solve(int l1, int r1, int l2, int r2){
	return query(root[r1], 1, n, l2, r2) - query(root[l1], 1, n, l2, r2);
}	

int main(){

	scanf("%d", &T);
	while (T--){
		tot = 0;
		scanf("%d", &n);
		rep(i, 1, n) a[i].scan();
		sort(a + 1, a + n + 1);

		for (int i = 1, j = 1; i <= n; ++i){
			root[i] = root[i - 1];
			for (; j <= n && a[j].l <= i; ++j)
				root[i] = ins(root[i], 1, n, a[j].r);
		}

		scanf("%d", &m);
		split = int(sqrt(n / log(n)) * 0.8);
		rep(op, 1, m){
			ans = 0;
			scanf("%d", &y);
			rep(i, 1, y) scanf("%d", x + i);
			sort(x + 1, x + y + 1);
			x[0] = 0, x[y + 1] = n + 1;

			if (y > split){
				s[0] = 0;
				for (int i = 1, j = 1; i <= n; ++i){
					s[i] = s[i - 1];
					for (; j <= n && x[j] <= i; ++j)
						++s[i];
				}
				rep(i, 1, n) ans += ((s[a[i].r] & 1) ^ (s[a[i].l - 1] & 1));
			}

			else{
				rep(i, 1, y){
					for (int j = i; j <= y; j += 2){
						ans += solve(x[i - 1], x[i], x[j], x[j + 1] - 1);
					}
				}
			}

			printf("%d\n", ans);
		}
	}

	return 0;
}

 

  

 

CodeChef February Challenge 2018 Chef and odd queries (分块 + 主席树)

标签:end   def   ++   log   ref   bit   题目   query   奇数   

原文地址:https://www.cnblogs.com/cxhscst2/p/8451370.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!