10.03T2 CDQ分治 codeforces

2、心与心的距离(heart)

就算发一千条短信,心与心的距离也不曾拉近过一厘米。

——《秒速五厘米》

 

题目描述:

那么,怎样才能将两颗心的距离拉近呢?小H独自走在飘雪的街头,思索着这个问题。

他停了下来,用脚尖在雪地上画出一个圈——要拉近心灵的距离,首先肉体上的距离不能太遥远。具体来说,整个世界就是一个数轴,每个人有一个坐标,还有个忍耐值,表示他能忍受的位置范围就是。如果有一个人j,不在这个范围内,那他就输在了距离上。

他又抬起头,看着路灯淡黄的光晕,突然想到:时间!每个人有一个最愿意与他人交往的时刻。两个人i,j,如果,那他们就输在了时间上。

“哦,我懂了”,小H微微一笑。具体来说,两个人i,j可以拉近心灵的距离当且仅且且。

现在请你计算能拉近心灵距离的人的对数。

注意(a,b),(b,a)只能计算一次。

 

输入格式:

第一行两真整数N,K,含义已在文中给出。

接下来n行,每行三个真整数,含义也已给出。

 

样例输入1

3 2

3 6 1

7 3 10

10 5 8

 

样例输入2

5 3

2 4 1

5 1 2

11 10 3

6 5 3

10 5 6

 

样例输出1

1

样例输出2

5

 

数据规模与约定:

,所有互不相同。

 

 

40分:

N^2,不解释了。

code:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<set>
 5 #define N 1000006
 6 using namespace std;
 7 struct node{
 8     int x,t,r;
 9 /*    bool operator<(const node&t)const{
10         return r<t.r;
11     }*/
12 }e[N];
13 int main(){
14     freopen("heart.in","r",stdin);
15     freopen("heart.out","w",stdout);
16     int n,k;
17     cin>>n>>k;
18     for(int i=1;i<=n;i++){
19         cin>>e[i].x>>e[i].r>>e[i].t;
20     }
21     int ans=0;
22     if(n<=1000){
23         for(int i=1;i<=n;i++){
24             for(int j=1;j<=n;j++){
25                 if(i==j)continue;
26                 if(abs(e[i].x-e[j].x)>min(e[i].r,e[j].r))continue;
27                 if(abs(e[i].t-e[j].t)>k)continue;
28                 ans++;
29             }
30         }
31         cout<<ans/2;
32         return 0;
33     }
34 }

最后20分:

其实这部分数据对你想出正解有一定提示作用,因为它告诉了你r是个比较重要的因素。

100分:

我们发现,对一个人i,如果我们既要考虑在i的忍受范围内的人,又要考虑这些人中,i又在哪些人的忍受范围之内,就特别难做。

对于两个人i,j,我们设,如果j在i的忍受范围之内,那么显然i也在j的忍受范围之内。所以我们先按r排序,这样,对于i,j(i<j)我们这需要考虑j是否在i的忍受范围之内就可以了。

具体做法有很多,我用的CDQ。先按r排序,然后递归下去,处理完左右区间后再分别按t排序处理。

CDQ的思想其实与归并排序有几分相似,在下面的代码里实际上左半边的R一定比右半边大,所以可以进行转移,因为两边的t都是有序的,所以找出来的符合t

条件的序列一定是连续的,我们选完t之后用树状数组维护一下编号就可以了,然后归并的时候就要按照t进行排序

 code:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define N 1000005
 5 #define tiao puts("!");
 6 using namespace std;
 7 struct node{
 8     int x,R,t,l,r;
 9 }e[N];
10 int ans,cc;
11 int c[N],d[N],tot;
12 bool cmp(node a,node b){
13     return a.R<b.R;
14 }
15 int lowbit(int x){
16     return x&(-x);
17 }
18 void add(int x,int v){
19     while(x<=cc){
20     //    cout<<"now->"<<x<<endl;
21         c[x]+=v;
22         x+=lowbit(x);
23     }
24 }
25 int n,k;
26 int query(int x){
27     int ans0=0;
28     while(x){
29         ans0+=c[x];
30         x-=lowbit(x);
31     }
32     return ans0;
33 }
34 bool bmp(const node &a,const node &b){
35     return a.t<b.t;
36 }
37 void clear(int x){
38     while(x<=cc){
39         c[x]=0;
40         x+=lowbit(x);
41     }
42 }
43 void cdq(int l,int r){
44     //cout<<"left="<<l<<"  right="<<r<<endl;
45     if(l==r)return;
46     int mid=l+r>>1;
47     cdq(l,mid);cdq(mid+1,r);//处理左右区间 
48     int head=mid+1,tail=mid;//找区间,现在是空集 
49     for(int i=l;i<=mid;i++){//找左边 ,因为右边的R是要比左边大的,所以右边一定可以忍受左边,避免了重复计数 
50         while(tail<r&&e[tail+1].t-e[i].t<=k){//找右边界 
51             tail++;
52             add(e[tail].x,1);
53         }
54         while(head<=tail&&e[i].t-e[head].t>k){//找左边界 
55             add(e[head].x,-1);
56             head++; 
57         }
58         ans+=query(e[i].r)-query(e[i].l-1);
59     }
60     for(int i=mid+1;i<=r;i++)clear(e[i].x);
61     inplace_merge(e+l,e+mid+1,e+r+1,bmp);
62 //    cout<<ans;
63 }
64 int main(){
65     freopen("heart.in","r",stdin);
66     freopen("heart.out","w",stdout);
67     cin>>n>>k;
68     for(int i=1;i<=n;i++){
69         cin>>e[i].x>>e[i].R>>e[i].t;
70         d[++tot]=e[i].x-e[i].R;
71         d[++tot]=e[i].x;
72         d[++tot]=e[i].x+e[i].R;
73     }
74     sort(d+1,d+tot+1);
75     cc=unique(d+1,d+tot+1)-d;    
76     for(int i=1;i<=n;i++){
77         e[i].l=lower_bound(d+1,d+cc,e[i].x-e[i].R)-d;
78         e[i].r=lower_bound(d+1,d+cc,e[i].x+e[i].R)-d;
79         e[i].x=lower_bound(d+1,d+cc,e[i].x)-d;
80     }
81     sort(e+1,e+n+1,cmp);
82     cdq(1,n);
83     cout<<ans;
84     return 0;
85 }

 

posted @ 2018-10-03 15:33  saionjisekai  阅读(49)  评论(0)    收藏  举报