2019河北省大学生程序设计竞赛:E-Paper Plane Fly Away

134 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第33天,点击查看活动详情

2019河北省大学生程序设计竞赛——E-Paper Plane Fly Away

E-Paper Plane Fly Away

题目描述

There are n boys, indexed from 1 to n, and n girls indexed from n+1 to 2n. One day, they have a party together. The girls are seated in the first row, and the boys sit in the second row. They take their seat in such a way, that a boy sit just behind a girl, and boy indexed 1 sit on the leftmost chair, 2 sit on the second, etc. Each boy has a girl he likes,and he may make contact to his sweetheart, by writing down what he wants to tell her on a piece of paper, and makes it a paper plane, which he will throw directly at her. You may assume that the plane will go in a straight line. But, the trouble occurs, when two paper plane collide in the air and drop halfway. Obviously, this will be extremely awkward. So each boy wants to know, if he throws his paper plane, how many paper planes have the potential to collide with it halfway. It's guaranteed that each girl is the sweetheart of exactly one boy.

输入描述:

The first line contains a single integer n.
Then n lines follow, the i-th of which contains two integers, the index of the girl seated in front of the i-th boy and the girl he likes.
1≤n≤10^5

输出描述:

Output n lines, the i-th of which contains one integer, the number of planes that may collide with i-th boy's plane.                   

输入

5
7 9
6 6
8 10
9 7
10 8

输出

3
2
2
3
2

问题解析

先以心爱的女生为顺序,给现实中坐在男生前面的女生打上序号。

比如样例中,心爱的女生顺序是:9、6、10、7、8,现实的女生是:7、6、8、9、10.

那么就把现实的女生序号改为:4、2、5、1、3。

此时就可以把问题转化成求逆序对的问题。

对于第i个女生,看左边有多少比她大的数,和右边有多少比她小的数。

两个结果相加,就是第i个男生的纸飞机会撞上的个数。

AC代码

int f[4 * N], a[N], res[N];
unordered_map<int,int>mymap;
void revise(int k, int l, int r, int x)
{
    if (l == r)
    {
        f[k]++;
        return;
    }
    int m = (l + r) / 2;
    if (x <= m)revise(k + k, l, m, x);
    else revise(k + k + 1, m + 1, r, x);
    f[k] = f[k + k] + f[k + k + 1];
}
​
int calc(int k, int l, int r, int x, int y)
{
    if (l == x && r == y)return f[k];
    int m = (l + r) / 2;
    if (y <= m)return calc(k + k, l, m, x, y);
    else
        if (x > m)return calc(k + k + 1, m + 1, r, x, y);
        else return calc(k + k, l, m, x, m) + calc(k + k + 1, m + 1, r, m + 1, y);
}
void solve()
{
    int n;
    cin >> n;
    vector<int>v(n+1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i] >> v[i];
        mymap[a[i]] = i;
    }
    for (int i = 1; i <= n; i++)
    {
        res[i] += calc(1, 1, n+1, mymap[v[i]], n);
        revise(1, 1, n+1, mymap[v[i]]);
    }
    memset(f, 0, sizeof f);
    for (int i = n; i >= 1; i--)
    {
        res[i] += calc(1, 1, n+1, 1, mymap[v[i]]);
        revise(1, 1, n+1, mymap[v[i]]);
    }
    for (int i = 1; i <= n; i++)cout << res[i] << endl;
}
​