题解 SP4226 【MSE06H - Japan】(树状数组+逆序对)

传送门

题目描述

 

日本计划迎接ACM-ICPC世界总决赛,为此必须修建大量道路。日本是一个高岛,东海岸有N个城市,西海岸有M个城市(M <= 1000, N <= 1000)。将修建K条高速公路。每个海岸的城市编号分别是1、2、……从北到南。每条高速公路都是一条直线,连接着东海岸的城市和西海岸的城市。建设资金由ACM担保。其中很大一部分是由高速公路之间的交叉点数量决定的。两条高速公路最多在一个地点相交。编写一个程序,计算高速公路之间的交叉点数量。

样例输入

1

3 4 4

1 4

2 3

3 2

3 1

样例输出

Test case 1: 5

分析

 

这道题一开始让我很雾......

不过 思路其实非常清晰:如果i<j a[i].x<a[j].x a[i].y>a[j].y 那么就会产生一个交点 大家画个图就出来了

具体操作也很好实现:

定义一个结构体 x升序排列 当x相同就y升序排列

按照我们的排序方式 把a[i].y踢出来跑树状数组求逆序对就可以了

附上AC代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1005;
int l,n,m,k,c[1005],a[1005];
long long ans=0;
struct nodee
{
    int x,y;
}qwq[N*N];
int lowbit(int x)
{
    return x&-x;
}
void add(int pos,int x)
{
    for(int i=pos;i<=n;i+=lowbit(i))
    {
        c[i]+=x;
    }
}
int query(int pos)
{
    long long sum=0;
    for(int i=pos;i>=1;i-=lowbit(i))
    {
        sum+=c[i];
    }
    return sum;
}
bool cmp(nodee a,nodee b)
{
    return (a.x<b.x)||((a.x==b.x)&&(a.y<b.y));
}
int main()
{
    scanf("%d",&l);
    for(int i=1;i<=l;i++)
    {
        memset(c,0,sizeof(c));
        memset(a,0,sizeof(a));
        scanf("%d%d%d",&n,&m,&k);
        for(int j=1;j<=k;j++)
        {
            scanf("%d%d",&qwq[j].x,&qwq[j].y);
        }
        sort(qwq+1,qwq+1+k,cmp);    
        ans=0;                                                                                                    
        for(int j=k;j>=1;j--)
        {
            add(qwq[j].y,1);
            ans+=query(qwq[j].y-1);
        }
    printf("Test case %d: %lld\n",i,ans);
    }
    return 0;
}

最后还是要插两句 我开始的逆序对用了离散化 并且在最后求逆序对跑的顺序 不知道为什么 在luogu,Virtual Judge和POJ都是RE,后来还变成了TLE(好过分嘤嘤嘤) 我不知道这是怎么肥四! 这道题应该可以跑归并 我没有尝试 大家有兴趣可以试试 贴一下我RE的代码 至今不知道错在哪 欢迎大佬指正

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=10005;
int l,n,m,k,c[N],a[N];
long long ans=0;
struct node
{
    int tot,num;
}qaq[N];
struct nodee
{
    int x,y;
}qwq[N];
int lowbit(int x)
{
    return x&-x;
}
void add(int pos,int x)
{
    for(int i=pos;i<=1005;i+=lowbit(i))
    {
        c[i]+=x;
    }
}
int query(int pos)
{
    long long sum=0;
    for(int i=pos;i>=1;i-=lowbit(i))
    {
        sum+=c[i];
    }
    return sum;
}
bool cmp(nodee a,nodee b)
{
    return (a.x<b.x)||((a.x==b.x)&&(a.y<b.y));
}
bool cmpp(node a,node b)
{
    return a.tot<b.tot;
}
int main()
{
    scanf("%d",&l);
    for(int i=1;i<=l;i++)
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int j=1;j<=k;j++)
        {
            scanf("%d%d",&qwq[j].x,&qwq[j].y);
        }
        sort(qwq+1,qwq+1+k,cmp);
        for(int j=1;j<=k;j++)
        {
            qaq[j].tot=qwq[j].y;
            qaq[j].num=j;
        }
        sort(qaq+1,qaq+1+k,cmpp);
        for(int j=1;j<=k;j++)
        {
            a[qaq[j].num]=j;
        }
        ans=0;
        for(int j=1;j<=k;j++)
        {
            add(a[j],1);
            ans+=(j-query(a[j]));
        }
    printf("Test case %d: %lld\n",i,ans);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/valentino/p/11142296.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值