- 题目:Paper Plane Fly Away
- 题意:有n个男孩从1到n按照左右顺序坐成一排,同样有n个女孩坐在男孩的前面(编号为n + 1 -> 2n),给出第i个男孩前面坐的的女生编号与该男生喜欢的女生编号。每个男孩要做一个情书飞机飞给喜欢的女孩,但是如果飞机的轨迹在空中相交飞机就会相互碰撞,现在你需要得到每个男生的飞机会和多少个其他男生的飞机相撞。
- 思路:用树状数组维护区间两次
- 解析:女生对应的位置编号可以从1->n进行编号;其次用逆序对的规律:从左往右遍历男生(编号依次增大)第i个男生喜欢的女生位置编号为mp[i],那么他后面的男孩喜欢的女孩位置编号比mp[i]小则都要发生撞击,访问到第i个男孩时直接看它喜欢的女孩mp[i]前面有几个女生仍然未被配对过,因为1->(i-1)的男孩肯定配对过,所以没配对的一定是第i个男生之后的男生,同理,从右到左再依此方法遍历一遍(这时候正好相反)
- 代码:
#include<bits/stdc++.h>
using namespace std;
map<int, int>mp; //girl的编号对应的位置号(从左到右1-n)
const int N = 1e5 + 5;
int g[N], l[N], r[N], res[N];
int n;
int lowbit(int x)
{
return x & (-x);
}
void addl(int x, int k)
{
while(x <= n)
{
l[x] += k;
x += lowbit(x);
}
}
void addr(int x, int k)
{
while(x <= n)
{
r[x] += k;
x += lowbit(x);
}
}
int queryl(int x)
{
int res = 0;
while(x)
{
res += l[x];
x -= lowbit(x);
}
return res;
}
int queryr(int x)
{
int res = 0;
while(x)
{
res += r[x];
x -= lowbit(x);
}
return res;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
int x;
cin >> x >> g[i]; //g[i]:第i个男生喜欢的女生编号
mp[x] = i; //第x号女生对应的位置
}
for(int i = 1; i <= n; i++)
{
g[i] = mp[g[i]];
addl(i, 1); //从左到右的树状数组置1
addr(i, 1); //从右到左的树状数组置1
}
for(int i = 1; i <= n; i++)
{
int pos = g[i];
res[i] += queryl(pos-1);
addl(pos, -1); //该女生已被碰撞则置0
g[i] = n - pos + 1;
}
for(int i = n; i >= 1; i--)
{
int pos = g[i];
res[i] += queryr(pos-1);
addr(pos, -1); //该女生已被碰撞则置0
}
for(int i = 1; i <= n; i++)
cout << res[i] << endl;
return 0;
}