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

ZSTU 4241 圣杯战争(ST表+二分)

时间:2017-11-28 13:24:27      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:int   pre   clu   区间查询   blank   def   nbsp   str   ons   

题目链接  ZSTU 4241

问题转化为有很多区间,现在每次给定一个区间求这个区间和之前所有区间中的某一个的交集的最大长度。

强制在线。

首先我们把所有的区间预处理出来。

然后去重(那些被包含的小区间可以去掉),再根据左端点升序排序。

这样的话这些区间的右端点也是严格升序的。

现在对于给定的$[x, y]$

所有区间大概可以分成三类。

1、左端点落在$[1, x - 1]$,对于这类区间查询右端点最大值即可。

2、右端点落在$[y + 1, n]$,对于这类区间查询左端点最小值即可。

3、除了上面两种的其他区间,对于这类区间查询区间长度最大值即可。

1、2直接利用单调性,二分找到满足条件的位置即可。

3的话……我选择了ST表。

最后答案不能超过给定区间的长度。

时间复杂度$O(nlogn)$

#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)

typedef long long LL;

const int N = 2e5 + 10;

struct node{
	int x, y;
	friend bool operator < (const node &a, const node &b){
		return a.x == b.x ? a.y > b.y : a.x < b.x;
	}
} b[N], c[N];

LL a[N], s[N], p[N];
int pos[N];
int n, m, q;
int T;
int num, cnt, ans;
int f[N][22];
int lg[N];

inline LL calc(int l, int r){ return s[r] - s[l - 1]; }

inline int solve(int l, int r){
	if (l > r) return 0;
	int k = lg[r - l + 1];
	return max(f[l][k], f[r - (1 << k) + 1][k]);
}

void work(){
	rep(i, 1, cnt) f[i][0] = c[i].y - c[i].x + 1;
	rep(j, 1, 20) rep(i, 1, cnt)
		if ((i + (1 << j) - 1) <= cnt) f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}

int main(){

	lg[1] = 0; rep(i, 2, 2e5) lg[i] = lg[i >> 1] + 1;

	scanf("%d", &T);
	while (T--){
		scanf("%d%d%d", &n, &m, &q);
		rep(i, 1, n) scanf("%lld", a + i);
		s[0] = 0;
		rep(i, 1, n) s[i] = s[i - 1] + a[i];
		rep(i, 1, m) scanf("%d", pos + i);
		rep(i, 1, m) scanf("%lld", p + i);
		num = 0;
		rep(i, 1, m){
			if (p[i] < a[pos[i]]) continue;
			int l = pos[i], r = n;
			while (l + 1 < r){
				int mid = (l + r) >> 1;
				if (calc(pos[i], mid) <= p[i]) l = mid;
				else r = mid - 1;
			}

			int t;
			if (calc(pos[i], r) <= p[i]) t = r; else t = l;
			++num;
			b[num].x = pos[i], b[num].y = t;
		}

		rep(i, 1, m){
			if (p[i] < a[pos[i]]) continue;
			int l = 1, r = pos[i];
			while (l + 1 < r){
				int mid = (l + r) >> 1;
				if (calc(mid, pos[i]) <= p[i]) r = mid;
				else l = mid + 1;
			}

			int t;
			if (calc(l, pos[i]) <= p[i]) t = l; else t = r;
			++num;
			b[num].x = t, b[num].y = pos[i];
		}
		
		sort(b + 1, b + num + 1);
		cnt = 0;
		for (int i = 1, j; i <= num; ){
			j = i + 1;
			while (j <= num && b[j].y <= b[i].y) ++j;
			c[++cnt] = b[i];
			i = j;
		}

		memset(f, 0, sizeof f);
		work();

		ans = 0;
		while (q--){
			int x, y;
			scanf("%d%d", &x, &y);
			x ^= ans;
			y ^= ans;
			if (x > y) swap(x, y);

			ans = 0;
			int X, Y;
			if (c[1].x >= x) X = 1;
			else{
				int l = 1, r = cnt;
				while (l + 1 < r){
					int mid = (l + r) >> 1;
					if (c[mid].x < x) l = mid; else r = mid - 1;
				}

				if (c[r].x < x){ X = r + 1; ans = max(ans, c[r].y - x + 1);}
				else{ X = l + 1; ans = max(ans, c[l].y - x + 1);}
			}

			if (c[cnt].y <= y) Y = cnt;
			else{
				int l = 1, r = cnt;
				while (l + 1 < r){
					int mid = (l + r) >> 1;
					if (c[mid].y > y) r = mid; else l = mid + 1;
				}

				if (c[l].y > y){ Y = l - 1; ans = max(ans, y - c[l].x + 1);}
				else{ Y = r - 1; ans = max(ans, y - c[r].x + 1); }
			}

			ans = max(ans, solve(X, Y));
			ans = min(ans, y - x + 1);
			printf("%d\n", ans);
		}
	}

	return 0;
}

  

ZSTU 4241 圣杯战争(ST表+二分)

标签:int   pre   clu   区间查询   blank   def   nbsp   str   ons   

原文地址:http://www.cnblogs.com/cxhscst2/p/7909238.html

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