有一些车要进洞和出洞,给出它们的进洞和出洞序列,如果有超车的情况发生,超车的那辆车要被罚款,即如果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;
}