codeforces 527D D. Clique Problem(二分+线段树+贪心+dp)
2015-08-10 16:49
190 查看
题目链接:
codeforces 527D题目大意:
给出一些点的xi和wix_i和w_i,当|xi−xj|≥wi+wj|x_i-x_j| \geq w_i+w_j的时候,两点间存在一条边,找出一个最大的集合,集合中的点两两之间存在边。题目分析:
首先我们想要知道哪些点之间是存在边的,|xi−xj|≥wi+wj|x_i-x_j| \geq w_i+w_j的绝对值符号去掉不影响边,因为不等式右边是加法,所以xi−xj≥wi+wj⇒xi−wi≥wj+xj\begin{align}
& x_i-x_j \geq w_i+w_j \\
& \Rightarrow x_i-w_i \geq w_j+x_j
\end{align}
所以我们可以先按照wj+xjw_j+x_j排序,那么xi,那么对于每个xix_i,我们只需要找到不大于xi−wix_i-w_i的j中的dp值最大的那个转移即可。区间最大通过线段树维护。利用二分找到比xi−wix_i-w_i小的最大的j,定为k
我们得到:
dp[i]=maxj=0kdp[j]+1dp[i] = \max_{j=0}^{k} dp[j] + 1
那么就是只考虑前面的这i个点得到的最大的点集的数量。
AC代码:
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #define INF (1<<29) #define MAX 200007 using namespace std; int n; struct Node { int w,x; bool operator < ( const Node& a ) const { return w+x < a.w+a.x; } }p[MAX]; int bsearch ( int i ) { int l = 0 , r = i-1 ,mid; while ( l != r ) { mid = (l+r+1)>>1; if ( p[i].x - p[i].w < p[mid].x + p[mid].w ) r = mid-1; else l = mid; } return l; } struct Tree { int l,r,maxn; }tree[MAX<<2]; void build ( int u , int l , int r ) { tree[u].l = l; tree[u].r = r; tree[u].maxn = 0; if ( l == r ) return; int mid = l+r>>1; build ( u<<1 , l , mid ); build ( u<<1|1 , mid+1 , r ); } void push_up ( int u ) { tree[u].maxn = max ( tree[u<<1].maxn , tree[u<<1|1].maxn ); } void update ( int u , int x , int v ) { int l = tree[u].l; int r = tree[u].r; if ( l == r ) { tree[u].maxn = v; return; } int mid = l+r>>1; if ( x > mid ) update ( u<<1|1 , x , v ); else update ( u<<1 , x , v ); push_up ( u ); } int query ( int u , int left , int right ) { int l = tree[u].l , r = tree[u].r; if ( left <= l && r <= right ) return tree[u].maxn; int mid = l+r>>1; int ret = 0; if ( l <= mid && r >= left ) ret = query ( u<<1 , left , right ); if ( left <= r && right > mid ) ret = max ( ret ,query ( u<<1|1 , left , right ) ); return ret; } int main () { while ( ~scanf ( "%d" , &n )) { for ( int i = 1 ; i <= n ; i++ ) scanf ( "%d%d" , &p[i].x , &p[i].w ); sort ( p+1 , p+n+1 ); build ( 1 , 0 , n ); update ( 1 , 0 , 0 ); p[0].x = - INF; p[0].w = - INF; int ans = 0; for ( int i = 1 ; i <= n ; i++ ) { int x = bsearch ( i ); //dp[i] = dp[x]+1; int v = query ( 1 , 0 , x ); update ( 1 , i , v+1 ); ans = max ( v+1 , ans ); } printf ( "%d\n" , ans ); } }
相关文章推荐
- 控件学习---UIImageView---摘自培训文档
- HDU5273.Dylans loves sequence(逆序数对)
- Integer Inquiry
- animate的{queue:false,duration:400}意思
- Django中的request.GET和request.POST
- Hdu oj 1005 Number Sequence
- UITableView 实现汽车品牌(demo)
- UIMenuController,UIPasteboard:复制,粘贴详细解释
- CodeForces 3D-Least Cost Bracket Sequence
- Flash Builder4.7破解方法
- 控件学习---UITextField---摘自培训资料
- MIUI 6 沉浸式状态栏(Android 4.4以上)
- UVA 1151 Buy or Build
- poj 1458/ hdu 1159 Common Subsequence
- Request的getParameter和getAttribute方法的区别
- Java之GUI编程(一)
- HDU 4027 Can you answer these queries? 线段树水题
- cpuid function
- HDOJ 5357 Easy Sequence DP
- leetcode 115 —— Distinct Subsequences