牛客网暑期ACM多校训练营(第六场) I.Team Rocket (思维+线段树)

题目链接

时间限制:C/C++ 4秒,其他语言8秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

There are n trains running between Kanto and Johto region. Assuming the railway is a number line, the i-th train travels from coordinate li to coordinate ri (both inclusive).

One day, m Team Rocket members invaded the railway system successfully. The i-th Team Rocket member was going to destroy the transportation hub with coordinate xi. Once a transportation hub within the driving range of a train is destroyed, the train's itinerary will be canceled immediately.

Giovanni wants to know how many train trips will be firstly canceled after each attack.

After all the attacks finished, for each train Giovanni needs to know that in which attack its itinerary was firstly canceled, or it was unaffected at all.

输入描述:

The input starts with one line containing exactly one integer T, which is the number of test cases.

For each test case, the first line contains two integers n and m, indicating the number of trains and the number of Team Rocket members.

Each of the next n lines contains 2 integers li and ri, indicating the driving range of the i-th train.

Each of the next m lines contains exactly one integer yi. , where xi is the transportation hub that Team Rocket members would destroy in the i-th attack, resi-1 is the product of the indexes of trips cancelled by the (i-1)-th attack and  means exclusive or. 

If no such trip exists, resi-1 is considered to be 0.

- 1 ≤ T ≤ 5.
- 1 ≤ n,m ≤ 2 x 105.
- -109 ≤ li ≤ ri ≤ 109.
- -109 ≤ xi ≤ 109.

输出描述:

For each test case, output one line "Case #x:" first, where x is the test case number (starting from 1).

Then output m lines, each line of which contains exactly one integer, indicating the number of train trips firstly canceled after the i-th attack.

Finally output one line, containing n integers, where the i-th integer is the time when the i-th train trip is firstly canceled or 0 if it is not affected.

示例1

输入

1
3 4
1 3
2 6
-999 1000000000
-1000
1
5
2

输出

Case #1:
0
2
1
0
2 3 2

题意:T组测试样例,每组先给出N和M表示有N条铁路和M次询问,随后给出N行L和R表示在数轴上当前铁路的位置,再给出M行Y,Y需要先与上一次询问得到的"所有被炸的铁路的下标的乘积%MOD"异或,然后作为新的爆炸点询问,输出要求对每次询问一个爆炸点,给出该爆炸点炸了几条铁路(被炸过的不算入内),最后在输出一行N个数,表示第1~N条铁路是在第几次询问被炸的(若没有被炸则为0).

题解:很显然这是一道防离线做法的题目(将每次的询问都异或上一次询问的一些特殊处理得到新的询问).这里我们考虑的做法是线段树维护该铁路系统,首先将所有铁路都编号从1~N,根据他们的L进行升序排序一波,然后作为线段树的叶子节点,最主要的处理是线段树维护的是该节点能到达的最大R值,那么对于每次被炸掉的铁路,我们考虑将其节点的R修改为-INF即可,至于在询问的时候,我们还需要考虑的是当前询问的爆炸点最左能炸到的铁路位置pos,之后二分的时候若是pos<mid+1,或当前爆炸点位置y大于当前树节点的R不用进入~从而将每次询问的时间复杂度压缩到O(logn),总的时间复杂度为O(nlogn).

代码如下:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<fstream>
using namespace std;
#define ll long long 
#define lson id<<1
#define rson id<<1|1
#define inf 0x3f3f3f3f
const ll mod = 998244353;
const int maxn = 2e5 + 10;
struct node {       
	int l, r, index;
	node(){}
	node(int L, int R, int id) {
		l = L, R = r, index = id;
	}
	bool operator <(const node &a)const {
		return l < a.l;
	}
}a[maxn], tre[maxn << 2];
ll y, res;
int cnt, pos;        //cnt用于记录炸了几条铁路,pos用于确定爆炸点在铁路升序排序后的位置
int ans[maxn];
void update(int id) {
	tre[id].r = max(tre[lson].r, tre[rson].r);
}
void build(int id, int L, int R) {
	if (L > R)return;
	if (L == R) {
		tre[id].r = a[L].r;
		tre[id].index = a[L].index;
		return;
	}
	int mid = L + R >> 1;
	build(lson, L, mid);
	build(rson, mid + 1, R);
	update(id);
}
void query(int id, int L, int R, int x) {
	if (L > R || y > tre[id].r) return;
	if (L == R) {
		cnt++;
		tre[id].r = -inf;
		res = (res*tre[id].index) % mod;
		ans[tre[id].index] = x;
		return;
	}
	int mid = L + R >> 1;
	query(lson, L, mid, x);
	if (pos >= mid + 1)
		query(rson, mid + 1, R, x);
	update(id);
}
int main() {
	int T, n, m, x;
	scanf("%d", &T);
	for (int t = 1; t <= T; t++) {
		memset(ans, 0, sizeof(ans));
		printf("Case #%d:\n", t);
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; i++) scanf("%d%d", &a[i].l, &a[i].r), a[i].index = i;
		sort(a + 1, a + 1 + n);
		build(1, 1, n);
		res = 0;
		for (int i = 1; i <= m; i++) {
			scanf("%lld", &y);
			y ^= res;
			cnt = 0; res = 1;
			pos = upper_bound(a + 1, a + 1 + n, node(y, 0, 0)) - a - 1;  
            //找到第一个大于y的位置-1
			if (pos > 0)
				query(1, 1, n, i);
			if (cnt == 0)
				res = 0;
			printf("%d\n", cnt);
		}
		for (int i = 1; i <= n; i++)
			printf("%d%c", ans[i], i == n ? '\n' : ' ');
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41156591/article/details/81481944