P3769 [CH弱省胡策R2]TATT(cdq套cdq)
cdq分治只会板子就来自己yy cdq套cdq的题(虽然也是板子)。被kdt吊打了2倍常数。不过没有确定出题人是否卡满了kdt,等会我去卡卡。
能自己yy出做法非常高兴,然后因为一个sb错误调了2h
首先按照第一维排序。然后仿照最长上升子序列定义状态:\(dp_i=\max\{dp_j+1\}(a_j\le a_i,b_j\le b_i,c_j\le c_i,d_j\le d_i)\) 。
由于排序,所以 \(a_j\le a_i\) 一定满足。
接下去考虑怎么限制三维。
由于是dp,记得中序遍历分治树,因为计算右区间的时候要求所有左区间的贡献已经计算完成,不然 \(dp_i\) 会偏小。
设当前分治到 \([l,r]\) ,按照第二维排序后给点打标记,\([l,mid]\) 内的标记为 \(1\) ,\([mid+1,r]\) 内的标记为 \(0\)
然后直接二维偏序(三、四两维)转移,在过程中只统计标记为 \(1\) 的对标记为 \(0\) 的点的贡献,这样就能带上第二维的限制了。
所以,如果再多几维,那么多打几层标记即可。当然再多几维就不会用cdq分治了qwq
-
小坑:有重复的点,先去重,然后给点赋权值,权值 \(w\) 为重复的个数,转移改成 \(dp_i=\max\{dp_j+w\}\) 。
-
我写代码时候一个奇葩的坑:一开始没注意到只用离散化d,把abcd一起离散化了,然后WA82。原因是树状数组忘记开 \(4\) 倍空间,然后因为洛谷的神秘O2高性能没有RE调了2h,不然早过了/kk
复杂度是两层cdq+树状数组=\(O(n\log^3 n)\) ,常数不大。但是为啥kdt \(O(n^{\frac{5}{3}})\) 会把这个\(\log^3\) 吊起来打啊/kk
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mkp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define sz(v) (int)v.size()
typedef long long LL;
typedef double db;
template<class T>bool ckmax(T&x,T y){return x<y?x=y,1:0;}
template<class T>bool ckmin(T&x,T y){return x>y?x=y,1:0;}
#define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
#define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i)
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f?x:-x;
}
const int N=50005;
int n,n_,len,lsh[N],dp[N],ans,tr[N];
struct node{
int a,b,c,d,s,op,id;
node(){a=b=c=d=op=id=0;}
inline bool operator == (const node&t)const{return a==t.a&&b==t.b&&c==t.c&&d==t.d;}
}a[N],b[N];
inline bool cmp1(const node&a,const node&b){return a.a!=b.a?a.a<b.a:a.b!=b.b?a.b<b.b:a.c!=b.c?a.c<b.c:a.d<b.d;}
inline bool cmp2(const node&a,const node&b){return a.b!=b.b?a.b<b.b:a.a!=b.a?a.a<b.a:a.c!=b.c?a.c<b.c:a.d<b.d;}
inline bool cmp3(const node&a,const node&b){return a.c<b.c;}
void upd(int x,int d){for(int i=x;i<=len;i+=i&-i)ckmax(tr[i],d);}
int ask(int x){int res=0;for(int i=x;i>0;i-=i&-i)ckmax(res,tr[i]);return res;}
void clr(int x){for(int i=x;i<=len;i+=i&-i)tr[i]=0;}
void cdq2(int l,int r){
if(l==r)return;
int mid=(l+r)>>1,i,j;
cdq2(l,mid),sort(a+l,a+mid+1,cmp3),sort(a+mid+1,a+r+1,cmp3);
for(i=mid+1,j=l;i<=r;++i){
for(;a[j].c<=a[i].c&&j<=mid;++j)if(a[j].op)upd(a[j].d,dp[a[j].id]);
if(!a[i].op)ckmax(dp[a[i].id],ask(a[i].d)+a[i].s);
}
for(--j;j>=l;--j)clr(a[j].d);
sort(a+mid+1,a+r+1,cmp2);
cdq2(mid+1,r);
}
void cdq1(int l,int r){
if(l==r)return;
int mid=(l+r)>>1;
cdq1(l,mid);
for(int i=l;i<=r;++i)a[i].op=i<=mid;
sort(a+l,a+r+1,cmp2);
cdq2(l,r);
sort(a+l,a+r+1,cmp1);
cdq1(mid+1,r);
}
signed main(){
n_=read();
rep(i,1,n_)b[i].a=read(),b[i].b=read(),b[i].c=read(),b[i].d=lsh[++len]=read();
sort(lsh+1,lsh+len+1),len=unique(lsh+1,lsh+len+1)-lsh-1;
rep(i,1,n_)b[i].d=lower_bound(lsh+1,lsh+len+1,b[i].d)-lsh;
sort(b+1,b+n_+1,cmp1);
for(int i=1,j=1;i<=n_;i=++j){
while(j<n_&&b[j+1]==b[i])++j;
a[++n]=b[i],a[n].s=j-i+1,a[n].id=n,dp[n]=a[n].s;
}
cdq1(1,n);
for(int i=1;i<=n;++i)ckmax(ans,dp[i]);
printf("%d\n",ans);return 0;
}
路漫漫其修远兮,吾将上下而求索