poj 3067 japan

题目大意:

有两条平行线,给出n条分别连接两条平行线上整点的线段

保证不会有重边且不会与两条以上边交于一个点的情况

思路:

画图可以得知,当且仅当两条线段在两条平行线上端点的大小关系相反时,才会相交

因此我们可以使用树状数组

按照第二条平行线上的位置升序排序

然后倒着查询之前有(即在它右边)几个比它在第一条平行线上位置小的就可以

但是有一个特殊情况:当他们在第二条平行线上位置相等时不算有交点

因此我们在排序时,若为特殊,则按照第一条的位置升序,就在倒着插入查询时可以避免错误的计算

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<queue>
 8 #include<vector>
 9 #include<set>
10 #include<map>
11 #include<stack>
12 #define inf 2147483611
13 #define ll long long
14 #define MAXN 1001001
15 using namespace std;
16 inline int read()
17 {
18     int x=0,f=1;
19     char ch=getchar();
20     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
21     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
22     return x*f;
23 }
24 struct data
25 {
26     int l,r;
27     bool operator < (const data &a) const
28     {
29         return (r<a.r)||(r==a.r&&l<a.l);
30     }
31 }a[MAXN];
32 int n,m,k,c[MAXN];
33 int lowbit(int x) {return x&(-x);}
34 void add(int x) {for(int i=x;i<=1010;i+=lowbit(i)) c[i]++;}
35 int sum(int x)
36 {
37     int ans=0;
38     for(int i=x;i;i-=lowbit(i))    ans+=c[i];
39     return ans;
40 }
41 int main()
42 {
43     ll ans;
44     int T=read();
45     for(int t=1;t<=T;t++)
46     {
47         memset(c,0,sizeof(c));
48         n=read(),m=read(),k=read();
49         for(int i=1;i<=k;i++) a[i].l=read(),a[i].r=read();
50         sort(a+1,a+k+1);
51         ans=0;
52         add(a[k].l);
53         for(int i=k-1;i>=1;i--)
54         {
55             ans+=sum(a[i].l-1);
56             add(a[i].l);
57         }
58         printf("Test case %d: %lld\n",t,ans);
59     }
60 }
View Code
posted @ 2017-10-11 21:21  jack_yyc  阅读(100)  评论(0编辑  收藏  举报