【USACO 2017 February Gold】Problem 3. Why Did the Cow Cross the Road III

题目大意:
给定长度为2N的序列,1~N各处现过2次,i第一次出现位置记为ai,第二次记为bi,对于每一对i∈[1,n],j∈[1,n]且i!=j,求满足ai<aj<bi<bj的对数.

Sample Input

4 
3
2
4
4
1
3
2
1
 

Sample Output

3
思路:

第一步,按照左端点排序。

第二步,我们只要再保证当前这一种数字的右端点在前面那些数字的右端点的右面就可以了,那么就对于这一种数字,把它的右端点插入树状数组,查询的时候查询当前这种数字a[i],b[i]之间的右端点的个数就是交叉对的个数了。


 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 int s[2000005],c[10000005],ans,n;
 6 struct node
 7 {
 8     int x,y;
 9 }e[1000005];
10 bool cmp(node a,node b)
11 {
12     return a.x<b.x;
13 }
14 void add(int l,int r,int k,int x)
15 {
16     if(l==r)
17     {
18         c[k]++;
19     }
20     else
21     {
22         int mid=(l+r)/2;
23         if(x<=mid)add(l,mid,k*2,x);
24         else add(mid+1,r,k*2+1,x);
25         c[k]=c[k*2]+c[k*2+1];
26     }
27 }
28 int ask(int l,int r,int k,int x,int y)
29 {
30     int mid=(l+r)/2;
31     if(l==x&&r==y)
32     {
33         return c[k];
34     }
35     else 
36     {
37         if(x>mid)return ask(mid+1,r,k*2+1,x,y);
38         else
39         {
40             if(y<=mid)return ask(l,mid,k*2,x,y);
41             else return(ask(l,mid,k*2,x,mid)+ask(mid+1,r,k*2+1,mid+1,y));
42         
43         }
44     }
45 }
46 int main()
47 {
48     freopen("circlecross.in","r",stdin);
49     freopen("circlecross.out","w",stdout);
50     scanf("%d",&n);
51     for(int i=1;i<=2*n;i++)
52     {
53         scanf("%d",&s[i]);
54         if(e[s[i]].x==0)e[s[i]].x=i;
55         else e[s[i]].y=i;
56     }
57     sort(e+1,e+n+1,cmp);
58     for(int i=1;i<=n;i++)
59     {
60         ans+=ask(1,2*n,1,e[i].x,e[i].y);
61         add(1,2*n,1,e[i].y);
62     }
63     printf("%d",ans);
64 }

 

 
posted @ 2020-06-13 17:06  HYDcn666_JZOJ  阅读(320)  评论(0编辑  收藏  举报