BZOJ2924 [Poi1998]Flat broken lines 【Dilworth定理 + 树状数组】

题目链接

BZOJ2924

题解

题面有误。。是\(45°\)

如果两个点间连线与\(x\)轴夹角在\(45°\)以内,那么它们之间连边
求最小路径覆盖 = 最长反链
由于\(45°\)比较难搞,我们利用复数翻转一下,逆时针旋转\(45°\)
这样就求一条从左上到右下的最长链
我们将所有点按\(x\)排序,令\(f[i]\)表示\(i\)结尾的最长链
那么

\[f[i] = max\{f[j] + 1\} \quad [j < i \; y_j > y_i] \]

离散化一下用树状数组优化

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
#define lbt(x) (x & -x)
using namespace std;
const int maxn = 30005,maxm = 100005,INF = 1000000000;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
	return out * flag;
}
struct point{
	double x,y; int d;
}p[maxn];
inline bool operator <(const point& a,const point& b){
	return a.x == b.x ? a.d < b.d : a.x < b.x;
}
int n,tot;
double b[maxn];
inline int getn(double x){return lower_bound(b + 1,b + 1 + tot,x) - b;}
int s[maxn],f[maxn];
void modify(int u,int v){while (u) s[u] = max(s[u],v),u -= lbt(u);}
int query(int u){int re = 0; while (u <= n) re = max(re,s[u]),u += lbt(u); return re;}
int main(){
	n = read(); double x,y,s2 = sqrt(2) / 2.0;
	REP(i,n){
		x = read(); y = read();
		p[i] = (point){s2 * (x - y),s2 * (x + y)};
		b[i] = p[i].y;
	}
	sort(b + 1,b + 1 + n); tot = 1;
	for (int i = 2; i <= n; i++) if (b[i] != b[tot]) b[++tot] = b[i];
	for (int i = 1; i <= n; i++) p[i].d = getn(p[i].y);
	sort(p + 1,p + 1 + n); int ans = 0;
	for (int i = 1; i <= n; i++){
		f[i] = query(p[i].d + 1) + 1;
		modify(p[i].d,f[i]);
		ans = max(ans,f[i]);
	}
	printf("%d\n",ans);
	return 0;
}

posted @ 2018-05-30 11:30  Mychael  阅读(164)  评论(0编辑  收藏  举报