codeforces 596C Wilbur and Points

题目链接:http://codeforces.com/problemset/problem/596/C

题意:1,在一张二维坐标轴上,有n (1 ≤ n ≤ 100 000) 个点,点坐标范围(0 ≤ x, y ≤ 100 000),对于每一个坐标i定义一个特定值为wi=yi-xi;

   2,给所有的点由1到n标号,标号要求:对于点h,所有满足横纵坐标均大于等于点h的点,其标号不能小于h的标号;

   3,所排列的点,点的位次即为其标号   

   4,给出一个特定值的序列,问是否有一个排列使得该序列的特定值顺序与所给出序列的特定值顺序相同,若没有,则输出“NO”;否则输出“YES”,并输出这个序列中点的坐标

 

我的做法:

    所能掌握的数据有:所有的点的坐标,可求出的wi值,给出的已知序列;所需要达到的目的为,在满足标号限制的前提下寻找到与所给序列相同的序列

    对标号的限制进行分析后,会发现:

假设中间的黄色点为目前正要标号的点;

1,蓝色点的标号一定是大于黄色点的,因为满足横纵坐标大于等于黄色点;

2,红色点的标号一定是小于黄色点的,因为满足横纵坐标小于等于黄色点;

3,周围的绿色点与黄色点并没有直接关系,因为他们不能满足横纵坐标均大于等于黄色点,而是满足横坐标或者纵坐标大于等于黄色点;

 

以上得出的一个结论为:

假设红色点数量为L,蓝色点数量为R,黄色点可能存在的标号为[L+1,n-R]:

综上,我们可以得出每个点i的可能存在范围,设为[Li,Ri];

 

然后所做的就是按照特定值对所给点进行排序,对于所给序列第i位的特定值,在所有点中二分查找有相同特定值的所有点(因为可能有多个,找到该区间的上边界和下边界即可),

对于满足特定值相等的所有点,筛选出其可能存在的范围[L,R]中包含当前位次的点,

而对于所有的满足条件的点,我们需要的是可能存在范围右边界更小的点,因为右边界更大的点可存在的位次范围更广,因为左边的点位次已经确定,而右边的点还未知,所以左边界没有比较的意义

 

可能犯愁的步骤为寻找点i的可存在范围:我们可以先将所有点按纵坐标由小到大排序,对于纵坐标相等的点按照横坐标由小到大进行排序,因为先出现的点必定为纵坐标比较小的点,纵坐标相等则横坐标小的先出现,之后按横坐标建树状数组计数,横坐标比当前点小的点必定纵坐标小于等于当前点,这样可以计算出红色点的数量;

至于蓝色点,逆循环即可,然后将点的横坐标变为(max-横坐标),之后跟计算红色点一样,即可计算出蓝色点;

附上代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100010
 4 int n,i,j,p,L,R,k,ma;
 5 int wi[N],ans[N];
 6 bool flag[N],ok;
 7 
 8 struct www{
 9     int x,y,L,R,w;
10 }A[N];
11 inline bool cmpco(const www&a,const www&b){
12     if(a.y!=b.y)return a.y<b.y;
13     return a.x<b.x;
14 }
15 inline bool cmpw(const www&a,const www&b){
16     return a.w<b.w;
17 }
18 
19 int tr[N];
20 inline void add(int x){while(x<=ma)tr[x]++,x+=x&-x;}
21 inline int sum(int x){int y=0;while(x)y+=tr[x],x-=x&-x;return y;}
22 
23 inline bool sou(int x){
24     int l,r,mid;
25     l=1,r=n;
26     while(l<r){
27         mid=l+((r-l)>>1);
28         if(A[mid].w>x)r=mid-1;
29         else if(A[mid].w==x)r=mid;
30         else l=mid+1;
31     }
32     L=l;
33     if(A[L].w!=x)return 0;
34     l=1,r=n;
35     while(l<r){
36         mid=l+((r-l+1)>>1);
37         if(A[mid].w>x)r=mid-1;
38         else if(A[mid].w==x)l=mid;
39         else l=mid+1;
40     }
41     R=r;
42     return 1;
43 }
44 
45 int main(){
46     scanf("%d",&n);
47     for(ma=-1,i=1;i<=n;i++){
48         scanf("%d%d",&A[i].x,&A[i].y);
49         A[i].x++,A[i].y++;
50         A[i].w=A[i].y-A[i].x;
51         if(A[i].x>ma)ma=A[i].x;
52     }
53     for(i=1;i<=n;i++)scanf("%d",&wi[i]);
54     sort(A+1,A+n+1,cmpco);
55     for(i=1;i<=n;i++)add(A[i].x),A[i].L=sum(A[i].x);
56     memset(tr,0,sizeof(tr));
57     for(i=n;i>=1;i--)add(ma-A[i].x+1),A[i].R=sum(ma-A[i].x+1);
58     sort(A+1,A+n+1,cmpw);
59     for(ok=1,i=1;i<=n;i++){
60         if(sou(wi[i])){
61             for(k=0,j=L;j<=R;j++)if(!flag[j]){
62                 if(A[j].L<=i&&A[j].R<=n-i+1)
63                     if(!k)k=j;
64                     else if(A[j].R>A[k].R)k=j;
65             }
66             if(k==0){ok=0;break;}
67             flag[k]=1,ans[i]=k;
68         }
69         else {ok=0;break;}
70     }
71     if(ok){
72         printf("YES\n");
73         for(i=1;i<=n;i++){
74             printf("%d %d\n",A[ans[i]].x-1,A[ans[i]].y-1);
75         }
76     }
77     else printf("NO\n");
78     return 0;
79 }

 
posted @ 2016-08-04 15:41  Aiky  阅读(262)  评论(0)    收藏  举报