clique
【题目描述】
数轴上有 n 个点,第 i 个点的坐标为 xi,权值为 wi。两个点 i,j 之
间存在一条边当且仅当 abs(xi-xj)>=wi+wj。
你需要求出这张图的最大团的点数。
(团就是两两之间有边的顶点
集合)
【输入数据】
第一行一个整数 n,接下来 n 行每行两个整数 xi,wi。
【输出数据】
一行一个整数表示答案。
【样例输入】
4
2 3
3 1
6 1
0 2
【样例输出】
3
【数据范围】
对于 20%的数据,n<=10。
对于 60%的数据,n<=1000。
对于 100%的数据,n<=200000,0<=|xi|,wi<=10^9。
先按x排序,则连边条件变为:
xi-xj>=wi+wj
xi-wi>=xj+wj
于是建边的条件可以理解为:有两个区间[xi-wi,xi+wi],[xj-wj,xj+wj],如果区间不相交那么连边
于是完全图就相当于求最长的不相交区间集
这里用的是dp+线段树+离散
把每一个xi+wi,xi-wi离散
然后每一次查询线段树上位于区间左边的最大f值
然后在线段树上更新当前右端点为当前f
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long lol; 7 struct Node 8 { 9 lol l,r; 10 }a[200001]; 11 lol c[1600001],n,m,s[400001],num,sz,f[200001],ans; 12 bool cmp(Node a,Node b) 13 { 14 return a.r<b.r; 15 } 16 lol query(int rt,int l,int r,int L,int R) 17 { 18 if (l>=L&&r<=R) 19 { 20 return c[rt]; 21 } 22 int mid=(l+r)/2; 23 lol s=0; 24 if (L<=mid) s=max(s,query(rt*2,l,mid,L,R)); 25 if (R>mid) s=max(s,query(rt*2+1,mid+1,r,L,R)); 26 c[rt]=max(c[rt*2],c[rt*2+1]); 27 return s; 28 } 29 void update(int rt,int l,int r,int x,lol d) 30 { 31 if (l==r) 32 { 33 c[rt]=max(c[rt],d); 34 return; 35 } 36 int mid=(l+r)/2; 37 if (x<=mid) update(rt*2,l,mid,x,d); 38 else update(rt*2+1,mid+1,r,x,d); 39 c[rt]=max(c[rt*2],c[rt*2+1]); 40 } 41 int main() 42 {int i; 43 lol w,x; 44 cin>>n; 45 for (i=1;i<=n;i++) 46 { 47 scanf("%lld%lld",&x,&w); 48 a[i].l=x-w;a[i].r=x+w; 49 s[++num]=x-w;s[++num]=x+w; 50 } 51 sort(a+1,a+n+1,cmp); 52 sort(s+1,s+num+1); 53 sz=unique(s+1,s+num+1)-(s+1); 54 //cout<<sz<<endl; 55 for (i=1;i<=n;i++) 56 { 57 a[i].l=lower_bound(s+1,s+sz+1,a[i].l)-s; 58 a[i].r=lower_bound(s+1,s+sz+1,a[i].r)-s; 59 } 60 for (i=1;i<=n;i++) 61 { 62 f[i]=query(1,1,sz,1,a[i].l)+1; 63 ans=max(ans,f[i]); 64 update(1,1,sz,a[i].r,f[i]); 65 } 66 cout<<ans; 67 }