poj 3067 Japan 树状数组求逆序对

本文介绍了一种算法,用于解决给定多个边对时如何快速计算任意两条边相交的数量问题。通过将边按一个端点排序并利用树状数组求逆序对的方法实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门


题目大意:
给出t个case,每个case给出k条边,这些边的左右两个端点分别属于n和m两个集合,求出有多少条相交的边(如果两条边有公共端点不算相交)


分析:
显然如果两条边相交一定满足(xi-xj)*(yi-yj)<0,所以我们可以把k条边按照x单调递增的顺序排排序,然后求y的逆序对即可(注意:如果两条边x相同,y按照递增的顺序排,因为这样处理时不会把这两条边算为相交的边Notice!!!)


代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
using namespace std;
const int maxn=1000+5;
int cas,n,m,k,t;
LL tr[maxn],ans,ONE=1;
struct road{
    int x,y;
}s[maxn*maxn];
bool cmp(road a,road b){
    if(a.x==b.x)
        return a.y<b.y;
    return a.x<b.x;
}
void add(int x,LL y){
    for(;x<=m;x+=(x&(-x)))
        tr[x]+=y;
}
LL query(int x){
    LL sum=0;
    for(;x;x-=(x&(-x)))
        sum+=tr[x];
    return sum;
}
signed main(void){
    scanf("%d",&cas),t=0;
    while(cas--){
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=k;i++)
            scanf("%d%d",&s[i].x,&s[i].y);
        sort(s+1,s+k+1,cmp);
        ans=0,memset(tr,0,sizeof(tr));
        for(int i=1;i<=k;i++)
            add(s[i].y,ONE),ans+=query(m)-query(s[i].y);
        t++;
        printf("Test case %d: %lld\n",t,ans);
    }
    return 0;
}

by >o< neighthorn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值