简化题面
求点数最多的四维偏序路径
解题思路
三维偏序可以直接第一层排序然后用(mathcal{CDQ})分治,转化成二位偏序问题来做,呢么四维偏序怎么做呢
(mathcal{Solution1})
众所周知,(mathcal{KD}) (tree)可以用来解决多维坐标问题,且在随机数据下复杂度很优秀,呢么我们来用(mathcal{KD}) (tree)来解决这个问题。
还是和四维偏序一样,先对第一位排序,我们用(mathcal{KD}) (tree)来维护三维的坐标
对于显然的(dp)方程我们有
[dp_i = max_{x_jle x_i,y_jle y_i,z_j le z_i} dp_j + 1
]
呢么我们维护三维范围内的最大值,每次查询的范围为(xin [-INF,x_i],yin [-INF,y_i],zin [-INF,z_i])内的最大值即可,然后每次结束之后插入节点,失衡时和替罪样树那样重构(mathcal{KD}) (tree)即可
(mathcal{Code1})
// Author: Ame__
#include<bits/stdc++.h>
#include<stdint.h>
#define _ 0
#define AME__DEBUG
#define bomb exit(0)
#define LOG(FMT...) fprintf(stderr , FMT)
#define TOWA(FMT...) fprintf(stdout , FMT)
using namespace std;
/*Grievous Lady*/
typedef int32_t i32;
typedef int64_t i64;
typedef double qwq;
const int BUF_SIZE = 1 << 12;
char buf[BUF_SIZE] , *buf_s = buf , *buf_t = buf + 1;
#define PTR_NEXT()
{
buf_s ++;
if(buf_s == buf_t)
{
buf_s = buf;
buf_t = buf + fread(buf , 1 , BUF_SIZE , stdin);
}
}
#define mians(_s_)
{
while(!isgraph(*buf_s)) PTR_NEXT();
char register *_ptr_ = (_s_);
while(isgraph(*buf_s) || *buf_s == '-')
{
*(_ptr_ ++) = *buf_s;
PTR_NEXT();
}
(*_ptr_) = ' ';
}
template <typename _n_> void mian(_n_ & _x_){
while(*buf_s != '-' && !isdigit(*buf_s)) PTR_NEXT();
bool register _nega_ = false; if(*buf_s == '-'){ _nega_ = true; PTR_NEXT(); }
_x_ = 0; while(isdigit(*buf_s)){ _x_ = _x_ * 10 + *buf_s - '0'; PTR_NEXT(); } if(_nega_) _x_ = -_x_;
}
const i32 INF = 0x3f3f3f3f;
const i32 kato = 2e5 + 10;
template <typename _n_> bool cmax(_n_ &a , const _n_ &b){ return a < b ? a = b , 1 : 0; }
template <typename _n_> bool cmin(_n_ &a , const _n_ &b){ return a > b ? a = b , 1 : 0; }
i32 n , ans;
struct point{
i32 a , b , c , d , val;
point(i32 a = 0 , i32 b = 0 , i32 c = 0 , i32 d = 0 , i32 val = 0): a(a) , b(b) , c(c) , d(d) , val(val){ }
friend bool operator !=(const point &x , const point &y){
return x.a != y.a || x.b != y.b || x.c != y.c || x.d != y.d;
}
}f[kato] , h[kato];
inline bool cmp1(const point &x , const point &y){
return x.b < y.b;
}
inline bool cmp2(const point &x , const point &y){
return x.c < y.c;
}
inline bool cmp3(const point &x , const point &y){
return x.d < y.d;
}
struct node{
i32 a , b , c , d;
node(i32 a = 0 , i32 b = 0 , i32 c = 0 , i32 d = 0): a(a) , b(b) , c(c) , d(d){ }
friend bool operator <(const node &x , const node &y){
return x.a ^ y.a ? x.a < y.a : x.b ^ y.b ? x.b < y.b : x.c ^ y.c ? x.c < y.c : x.d < y.d;
}
}g[kato];
namespace towa{
struct node{
node *ls , *rs;
point p;
i32 b1 , b2 , c1 , c2 , d1 , d2 , val , mval , size;
node(){ }
node(const point &qaq): p(qaq){
ls = rs = 0x0 , b1 = b2 = p.b , c1 = c2 = p.c , d1 = d2 = p.d , mval = val = p.val , size = 1;
}
inline void up1(node *x){
this -> b1 = min(this -> b1 , x -> b1) , this -> b2 = max(this -> b2 , x -> b2);
this -> c1 = min(this -> c1 , x -> c1) , this -> c2 = max(this -> c2 , x -> c2);
this -> d1 = min(this -> d1 , x -> d1) , this -> d2 = max(this -> d2 , x -> d2);
}
inline void up2(){
mval = max(this -> val , max(this -> ls ? this -> ls -> mval : -INF , this -> rs ? this -> rs -> mval : -INF));
size = (this -> ls ? this -> ls -> size : 0) + (this -> rs ? this -> rs -> size : 0) + 1;
}
}*root , _pool[kato] , *tail = _pool , *sta[kato];
i32 top , tot;
inline node *build(node *fa , i32 l , i32 r , i32 opt){
if(l > r) return 0x0;
i32 mid = (l + r) >> 1;
nth_element(h + l , h + mid , h + r + 1 , opt == 1 ? cmp2 : opt == 2 ? cmp3 : cmp1);
node *o = new(top ? sta[top --] : tail ++) node(h[mid]);
o -> ls = build(o , l , mid - 1 , (opt + 1) % 3);
o -> rs = build(o , mid + 1 , r , (opt + 1) % 3);;
if(o -> ls) o -> up1(o -> ls);
if(o -> rs) o -> up1(o -> rs);
o -> up2();
return o;
}
inline void del(node *&o){
if(!o) return;
if(o -> ls) del(o -> ls);
if(o -> rs) del(o -> rs);
h[++ tot] = o -> p , sta[++ top] = o;
}
inline void judge(node *&o , i32 opt){
tot = 0; i32 res = o -> size;
if(0.725 * o -> size <= static_cast<qwq>(max(o -> ls ? o -> ls -> size : 0 , o -> rs ? o -> rs -> size : 0))) del(o) , o = build(0x0 , 1 , res , opt);
}
inline void insert(node *&o , const point &a , i32 opt){
if(!o) return void(o = new(top ? sta[top --] : tail ++) node(a));
if(opt == 2){
if(a.d <= o -> p.d) insert(o -> ls , a , (opt + 1) % 3);
else insert(o -> rs , a , (opt + 1) % 3);
}else if(opt == 1){
if(a.c <= o -> p.c) insert(o -> ls , a , (opt + 1) % 3);
else insert(o -> rs , a , (opt + 1) % 3);
}else{
if(a.b <= o -> p.b) insert(o -> ls , a , (opt + 1) % 3);
else insert(o -> rs , a , (opt + 1) % 3);
}
if(o -> ls) o -> up1(o -> ls);
if(o -> rs) o -> up1(o -> rs);
o -> up2();
judge(o , opt);
}
inline i32 ask(node *o , i32 b1 , i32 b2 , i32 c1 , i32 c2 , i32 d1 , i32 d2){
if(!o || b2 < o -> b1 || b1 > o -> b2 || c2 < o -> c1 || c1 > o -> c2 || d2 < o -> d1 || d1 > o -> d2) return 0;
if(b1 <= o -> b1 && o -> b2 <= b2 && c1 <= o -> c1 && o -> c2 <= c2 && d1 <= o -> d1 && o -> d2 <= d2) return o -> mval;
i32 res = 0;
if(b1 <= o -> p.b && o -> p.b <= b2 && c1 <= o -> p.c && o -> p.c <= c2 && d1 <= o -> p.d && o -> p.d <= d2) res = max(res , o -> val);
return max(res , max(ask(o -> ls , b1 , b2 , c1 , c2 , d1 , d2) , ask(o -> rs , b1 , b2 , c1 , c2 , d1 , d2)));
}
}
inline int Ame_(){
#ifdef AME__
freopen(".in" , "r" , stdin); freopen(".out" , "w" , stdout); int nol_cl = clock();
#endif
mian(n);
for(i32 i = 1;i <= n;i ++) mian(g[i].a) , mian(g[i].b) , mian(g[i].c) , mian(g[i].d);
sort(g + 1 , g + 1 + n);
for(i32 i = 1;i <= n;i ++) f[i] = (point){0 , g[i].b , g[i].c , g[i].d};
for(i32 i = 1;i <= n;i ++){
i32 res = towa::ask(towa::root , -INF , f[i].b , -INF , f[i].c , -INF , f[i].d) + 1;
f[i].val = res;
ans = max(ans , res);
towa::insert(towa::root , f[i] , 0);
}
TOWA("%d
" , ans);
#ifdef AME__TIME
LOG("Time: %dms
", int((clock() - nol_cl) / (qwq)CLOCKS_PER_SEC * 1000));
#endif
return ~~(0^_^0); /*さようならプログラム*/
}
int Ame__ = Ame_();
int main(){;}
(mathcal{Solution2})
(mathcal{CDQ})套(mathcal{CDQ}),暂时鸽鸽鸽