1. 程式人生 > >3067 Japan (樹狀陣列 思維)

3067 Japan (樹狀陣列 思維)

題意:

       日本東海岸有N個城市(從北到南命名為1, 2, ..., N),西海岸有M個城市(從北到南命名為1, 2, ..., M),東西之間有K條高速公路,問這K條高速公路有多少個交叉點(一個交叉點有且只有兩條高速公路經過)(1000 <= N, M <= 1000)。

題解:

       記每條高速公路為(x,y), 即東岸的第x個城市與西岸的第y個城市修一條路。當兩條路有交點時,滿足(x1-x2)*(y1-y2) < 0。所以,將每條路按x從小到達排序,若x相同,按y從小到大排序。 然後按排序後的公路用樹狀陣列線上更新,求y的逆序數之 和 即為交點個數。

題目沒給k的範圍,沒給T的範圍......

自己試了一下這個題陣列開到1e6就過了,1e5還不行,最後的結果需要開long long

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define maxn 400010
#define pr printf
using namespace std;
#define ll long long
#define pr pair<int,int>
#define maxn 1000000
pr a[maxn];
int c[maxn];
int n,m,k;
bool cmp(pr x,pr y)
{
    if(x.first==y.first)
        return x.second<y.second;
    return x.first<y.first;
}
inline int lowbit(int x)
{
    return x & -x;
}
inline void add(int i,int val)
{
    while(i<=m)
    {
        c[i]+=val;
        i+=lowbit(i);
    }
}
inline int sum(int i)
{
    int s=0;
    while(i>0)
    {
        s+=c[i];
        i-=lowbit(i);
    }
    return s;
}
int main()
{
    //freopen("input.txt","r",stdin);
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;++cas)
    {
        for(int i=0;i<=maxn;++i)
            c[i]=0;
        //memset(c,0,sizeof(c));
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=k;++i)
            scanf("%d%d",&a[i].first,&a[i].second);
        sort(a+1,a+1+k,cmp);
        ll ans=0;
        for(int i=1;i<=k;++i)
        {
            add(a[i].second,1);//有點的地方就是1,沒點的地方就是0
            ans+=i-sum(a[i].second);
        }
        printf("Test case %d: %lld\n",cas,ans);
    }

    return 0;
}