Loading

P3769 [CH弱省胡策R2]TATT(cdq套cdq)

P3769 [CH弱省胡策R2]TATT

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;
}
posted @ 2021-01-05 18:29  zzctommy  阅读(99)  评论(0编辑  收藏  举报