CCPC2019河北省赛 E.Paper Plane Fly Away

  • 题目: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;
}

上一篇:关于红眼梗


下一篇:大千世界中,万物皆有时节