P3660 [USACO17FEB]Why Did the Cow Cross the Road III G

链接
简单的树状数组

题意

现在告诉了你一个线段上有2*n个点,告诉了你每个点从这条线段上的那个点进入,那个点出去,让你求交叉的点的对数

思路

在这里插入图片描述

如图所示,按照题目中给出的案例,我们发现了一共有三对交叉的点,那么怎么求呢?
我们先观察与3这个点交叉的点,分别是2和1,假设最开始我们线连接3这个点的进入点和出入点,然后顺次连2,会发现这个时候会有一个交叉对,我们发现,3和2相交满足的条件是:3的左端点位于2的左端点的左侧,3的右端点位于2的右端点的右边,(4不和任何点相交,我们就不考虑了),再来添加1这个点,当我们添加1这个点的时候会多出两个交叉点,会发现与1相交的原理是,1的起点和终点之间有3和2的有段点,那么规律就出来了,我们每次添加的时候,只需要看添加的这段区间里面有没有某个点的右端点即可。
现在我们使用树状数组来做,我先现在不管是那个点,只需要管加入的区间即可,我们按照左区间从小到大进行排序,每加入一个,我们将答案更新,加上加入的这段区间里面的右端点的数量,更新了之后,在激昂当前区间的右端点更新到树状数组上面即可。

#include <bits/stdc++.h>

#define int long long

using namespace std;

const int N = 1e5 + 10;

int n;
int tr[N];
bool vis[N];

struct node
{
    int l, r;
    bool operator < (const node &t) const { return l < t.l; }
}a[N];

int lowbit(int x) { return x & -x; }

void add(int x) { for (int i = x; i <= 2 * n; i += lowbit(i)) tr[i] += 1; }

int Sum(int x)
{
    int sum = 0;
    for (int i = x; i; i -= lowbit(i)) sum += tr[i];
    return sum;
}

signed main()
{
    std::ios::sync_with_stdio(false);

    cin >> n;
    for (int i = 1; i <= 2 * n; i ++)
    {
        int x; cin >> x;
        if (!vis[x]) { a[x].l = i; vis[x] = 1; }
        else a[x].r = i;
    }

    sort(a + 1, a + 1 + n);

    int ans = 0;
    for (int i = 1; i <= n; i ++)
    {
        ans += (Sum(a[i].r) - Sum(a[i].l - 1));
        add(a[i].r);
    }

    cout << ans << endl;

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值