codeforces global round 5 B题权值线段树

有一些车要进洞和出洞,给出它们的进洞和出洞序列,如果有超车的情况发生,超车的那辆车要被罚款,即如果a比b先进洞,但是b却先出洞,b就要被罚款。

这个题有很多的方法,但是终究都围绕着一个思想:比自己先进洞的车一定要先出洞,否则就要被罚款。

我看了大佬的博客,这题用树状数组写的,思想是按照出洞的顺序,找出这辆车的前面本应该有多少辆车已经出洞了。再找实际上有多少辆车出洞了。如果实际上的更少,就要被罚款。然后再把这辆车加入树状数组中,更新树状数组。

我的做法是用权值线段树做,其实差不多,只是写法不同。

#pragma warning(disable:4996)
#include
#include
#include
#include
#include
#include
using namespace std; 
typedef long long ll;
const int maxn = 100005;
int a[maxn], b[maxn], pos[maxn];
struct node
{
	//num代表权值,表示数量
	int l, r, num;
};
node tree[maxn << 2];
//建树
void build(int L, int R, int k)
{
	tree[k].l = L; tree[k].r = R;
	if (L == R)
	{
		tree[k].num = 0;
		return;
	}
	int mid = (L + R) / 2;
	build(L, mid, 2 * k);
	build(mid + 1, R, 2 * k + 1);
	tree[k].num = tree[2 * k].num + tree[2 * k + 1].num;
}
//权值线段树单点更新
void update(int k, int p)
{
	if (tree[k].l == tree[k].r)
	{
		tree[k].num = 1;
		return;
	}
	int mid = (tree[k].l + tree[k].r) / 2;
	if (p <= mid)update(2 * k, p);
	else update(2 * k + 1, p);
	tree[k].num = tree[2 * k].num + tree[2 * k + 1].num;
}
//区间查询,查询前面有多少辆车
int query(int k, int L, int R)
{
	if (tree[k].l >= L && tree[k].r <= R)
	{
		return tree[k].num;
	}
	int mid = (tree[k].l + tree[k].r) / 2;
	int sum = 0;
	if (L <= mid)sum += query(2 * k, L, R);
	if (R > mid)sum += query(2 * k + 1, L, R);
	return sum;
}
int main()
{
	int n, i, ans;
	while (scanf("%d", &n) == 1)
	{
		memset(tree, 0, sizeof(tree));
		//pos代表每辆车进洞的顺序
		for (i = 1; i <= n; i++)
		{
			scanf("%d", &a[i]);
			pos[a[i]] = i;
		}
		for (i = 1; i <= n; i++)
			scanf("%d", &b[i]);
		build(1, n, 1);
		int t; ans = 0;
		for (i = 1; i <= n; i++)
		{
			//t代表在b[i]前面有多少辆车
			t = query(1, 1, pos[b[i]]);
			//pos[b[i]]-1代表这辆车前面本应该有多少辆车
			if (t < pos[b[i]]-1)ans++;
			update(1, pos[b[i]]);
		}
		printf("%d\n", ans);
	}
	return 0;
}

 

你可能感兴趣的:(线段树,ACM的人生)