1. 程式人生 > >codeforces 527D D. Clique Problem(二分+線段樹+貪心+dp)

codeforces 527D D. Clique Problem(二分+線段樹+貪心+dp)

題目連結:

題目大意:

給出一些點的xiwi,當|xixj|wi+wj的時候,兩點間存在一條邊,找出一個最大的集合,集合中的點兩兩之間存在邊。

題目分析:

  • 首先我們想要知道哪些點之間是存在邊的,|xixj|wi+wj的絕對值符號去掉不影響邊,因為不等式右邊是加法,所以
    xixjwi+wjxiwiwj+xj
    所以我們可以先按照wj+xj排序,那麼xi,那麼對於每個xi,我們只需要找到不大於xiwi的j中的dp值最大的那個轉移即可。區間最大通過線段樹維護。利用二分找到比xiwi小的最大的j,定為k
    我們得到:
    dp[i]=maxj=0kdp[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 ); } }