相遇点对 & 数点问题

题意:

  一个长为l的环,环上有n个点,每个点以一定的速度顺时针或逆时针运动,两个点相遇即某一时刻内两个点位置相同.

  求有多少点对相遇----相同点对出现多次仅统计一次.

 

SOL:

  考试的时候想到用线段树或者树状数组统计的...但是被数据范围吓住了然后就没打...毕竟是一个差不多n^2logn的东西...然而n有10000....

  事实证明数据结构题你要往小里想...胆大心细...

  

  怎么统计呢(这才是正事!!!)...  显然我们能把环上的运动放到直线上. 考虑两个点a,b的追及问题,若a在b身后(我们假设两个点运动方向相同),那么如果两个点在某一时刻相遇,那么a的速度一定大于b,则当他们运动ts后a的一定在b身前.

  这是一个非常有用的性质,当我们将每个点的初始位置排序后,所有能与这个点相遇的最终位置坐标一定小于它,那么我们离散化后用树状数组统计即可

  对于方向不同的点,减个L相同考虑就完啦...

/*==========================================================================
# Last modified: 2016-03-01 08:27
# Filename: t1.cpp
# Description: 
==========================================================================*/
#define me AcrossTheSky 
#include <cstdio> 
#include <cmath> 
#include <ctime> 
#include <string> 
#include <cstring> 
#include <cstdlib> 
#include <iostream> 
#include <algorithm> 
  
#include <set> 
#include <map> 
#include <stack> 
#include <queue> 
#include <vector> 
 
#define lowbit(x) (x)&(-x) 
#define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++) 
#define FORP(i,a,b) for(int i=(a);i<=(b);i++) 
#define FORM(i,a,b) for(int i=(a);i>=(b);i--) 
#define ls(a,b) (((a)+(b)) << 1) 
#define rs(a,b) (((a)+(b)) >> 1) 
#define getlc(a) ch[(a)][0] 
#define getrc(a) ch[(a)][1] 
 
#define maxn 100000 
#define maxm 100000 
#define pi 3.1415926535898 
#define _e 2.718281828459 
#define INF 1070000000 
using namespace std; 
typedef long long ll; 
typedef unsigned long long ull; 
 
template<class T> inline 
void read(T& num) { 
    bool start=false,neg=false; 
    char c; 
    num=0; 
    while((c=getchar())!=EOF) { 
        if(c=='-') start=neg=true; 
        else if(c>='0' && c<='9') { 
            start=true; 
            num=num*10+c-'0'; 
        } else if(start) break; 
    } 
    if(neg) num=-num; 
} 
/*==================split line==================*/ 
struct Node{
	int l,r,pos;
}a[maxn];
int e[maxn],c[2][maxn],ans=0,n;
int cmp(Node x,Node y){return x.l<y.l;}
void add(int k,int i,int v){
	while (i<=n){
		c[k][i]+=v;
		i+=lowbit(i);
	}
}
int sum(int k,int i){
	int ret=0;
	while (i){
		ret+=c[k][i];
		i-=lowbit(i);
	}
	return ret;
}
int get(int x){
	int L=0,R=n,mid;
	while (L<=R){
		mid=(L+R)>>1;
		if (e[mid]<=x) L=mid+1; else R=mid-1;
	}
	return L-1;
}
int main(){
	//freopen("a.in","r",stdin);
	int l,t; 
	read(l); read(t); read(n);
	FORP(i,1,n){
		read(a[i].l); a[i].l%=l;
		int x; read(x); a[i].r=a[i].l+x*t;
		e[i]=a[i].r;
	}
	sort(e+1,e+1+n); sort(a+1,a+1+n,cmp);
	e[0]=-INF;
	FORP(i,1,n) {
		a[i].pos=lower_bound(e+1,e+1+n,a[i].r)-e;
		add(0,a[i].pos,1);
	}
	int i;
	FOR(i,1,n){
		int j;
		for (j=i;j<n && a[j+1].l==a[j].l;j++);
		FORP(k,i,j) add(0,a[k].pos,-1);
		FORP(k,i,j){
			ans+=sum(0,a[k].pos);
			ans+=sum(1,get(a[k].r-l));//sum(1,lower_bound(e+1,e+1+n,(a[k].r-l))-e);
		}
		FORP(k,i,j) add(1,a[k].pos,1);
		ans+=(j-i)*(j-i+1)/2;
		i=j;
	}
	printf("%d\n",ans);
}

 

你可能感兴趣的:(相遇点对 & 数点问题)