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 }

浙公网安备 33010602011771号