P5621 [DBOI2019] 德丽莎世界第一可爱

前言

我们可以发现这就是一个四维偏序,那么我们就可以采用 cdq 套 cdq 来解决它,然后这里还有两个双倍经验。

思路

我们可以得出一个 \(n^2\) dp,用 \(f_i=\max(f_j+val_i)\) 其中的 \(j\) 要满足四维不大于 \(i\)

首先我们可以一维一维的来考虑。

对于第一维,和三位偏序一样直接排序即可。

il bool cmpa(node a,node b) {
	if(a.a!=b.a) return a.a<b.a;
	if(a.b!=b.b) return a.b<b.b;
	if(a.c!=b.c) return a.c<b.c;
	return a.d<b.d;
}

然后我们就需要来考虑如何既保证第 \(1\) 维有序有保证第 \(2\) 维有序,这里我们可以采用一种标记的形式(毕竟我们只需要加上 \(l\sim mid\)\(mid+1\sim r\) 互相的贡献)所以我们这里将 \(l\sim mid\) 标记成一种颜色再将 \(mid+1\sim r\) 标记成另一种颜色即可,然后我们在对于第 \(2\) 维进行排序再去算第 \(3\) 维即可。

bool cmpb(node a,node b) {
	if(a.b!=b.b) return a.b<b.b;
	if(a.c!=b.c) return a.c<b.c;
	if(a.d!=b.d) return a.d<b.d;
	return a.a<b.a;
}
void cdq(int l,int r) {
	if(l==r) return ;
	int mid=l+r>>1;
	cdq(l,mid);
	rep(i,l,r) pb[i]=s[i],pb[i].f=(i<=mid?1:2);
	sort(pb+l,pb+r+1,cmpb);
	cdq2(l,r);
	cdq(mid+1,r);
}

这里我们按照三位排序的方法处理最后一维(树状数组)然后我们按照三维排序(分为 \(l\sim mid\)\(mid+1\sim r\) 分别排序,因为需要保证第 \(2\) 维的顺序)的方法先将第三维排序再用双指针去看,如果一个在 \(l\sim mid\) 的值被标记为了在 \(L\sim Mid\)(这里表示再上面的标记中标记为了 \(1\)) 中 ,就将它的贡献加入树状数组,然后如果遍历到了一个 \(mid+1\sim r\) 的一个的标记为 \(2\) 就可以取最大值,只需要用树状数组处理出最大值即可。

void cdq2(int l,int r) {
	if(l==r) return ;
	int mid=l+r>>1;
	cdq2(l,mid);
	rep(i,l,r) pc[i]=pb[i];
	sort(pc+l,pc+1+mid,cmpc);
	sort(pc+mid+1,pc+1+r,cmpc);
	int j=l;
	for(int i=mid+1;i<=r;i++) {
		while(pc[i].c>=pc[j].c&&j<=mid) {
			if(pc[j].f==1) add(pc[j].d,f[pc[j].id]);
			j++;
		}
		if(pc[i].f==2) f[pc[i].id]=max(f[pc[i].id],Ans(pc[i].d)+pc[i].e);
	}
	rep(i,l,mid) if(pc[i].f==1) clean(pc[i].d);
	cdq2(mid+1,r);
}

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define rep1(i,x,y) for(register int i=x;i>=y;--i)
#define in(x) scanf("%lld",&x)
#define fire signed
#define il inline
il void print(int x) {
	if(x<0) putchar('-'),x=-x;
	if(x>=10) print(x/10);
	putchar(x%10+'0');
}
int T;
int n,tot;
const int N=5e4+10,M=2e5+10;
struct node{
	int a,b,c,d,e;
	int f,id;
}p[N],s[N],pb[N],pc[N];
il bool cmpa(node a,node b) {
	if(a.a!=b.a) return a.a<b.a;
	if(a.b!=b.b) return a.b<b.b;
	if(a.c!=b.c) return a.c<b.c;
	return a.d<b.d;
}
bool cmpb(node a,node b) {
	if(a.b!=b.b) return a.b<b.b;
	if(a.c!=b.c) return a.c<b.c;
	if(a.d!=b.d) return a.d<b.d;
	return a.a<b.a;
}
bool cmpc(node a,node b) {
	if(a.c!=b.c) return a.c<b.c;
	if(a.d!=b.d) return a.d<b.d;
	if(a.a!=b.a) return a.a<b.a;
	return a.b<b.b;
}
int f[N];
int tr[M];
int idx;
int lowbit(int x) {
	return x&-x;
}
void add(int x,int k) {
	for(;x<=idx;x+=lowbit(x)) tr[x]=max(tr[x],k);
}
int Ans(int x) {
	int res=-INT_MAX;
	for(;x;x-=lowbit(x)) res=max(res,tr[x]);
	return res;
}
void clean(int x) {
	for(;x<=idx;x+=lowbit(x)) tr[x]=-1000100000000000;
}
bool cmp(node a,node b) {
	return a.d<b.d;
}
unordered_map<int,int>mp;
int getd(int x) {
	if(!mp[x]) mp[x]=++idx;
	return mp[x];
}
void cdq2(int l,int r) {
	if(l==r) return ;
	int mid=l+r>>1;
	cdq2(l,mid);
	rep(i,l,r) pc[i]=pb[i];
	sort(pc+l,pc+1+mid,cmpc);
	sort(pc+mid+1,pc+1+r,cmpc);
	int j=l;
	for(int i=mid+1;i<=r;i++) {
		while(pc[i].c>=pc[j].c&&j<=mid) {
			if(pc[j].f==1) add(pc[j].d,f[pc[j].id]);
			j++;
		}
		if(pc[i].f==2) f[pc[i].id]=max(f[pc[i].id],Ans(pc[i].d)+pc[i].e);
	}
	rep(i,l,mid) if(pc[i].f==1) clean(pc[i].d);
	cdq2(mid+1,r);
}
void cdq(int l,int r) {
	if(l==r) return ;
	int mid=l+r>>1;
	cdq(l,mid);
	rep(i,l,r) pb[i]=s[i],pb[i].f=(i<=mid?1:2);
	sort(pb+l,pb+r+1,cmpb);
	cdq2(l,r);
	cdq(mid+1,r);
}
void solve() {
	in(n);
	int ans=-INT_MAX;
	rep(i,1,n) cin>>p[i].a>>p[i].b>>p[i].c>>p[i].d>>p[i].e,ans=max(ans,p[i].e);
	sort(p+1,p+1+n,cmp);
	rep(i,1,n) p[i].d=getd(p[i].d);
	sort(p+1,p+1+n,cmpa);
	int sum=false;
	rep(i,1,n) {
		sum+=p[i].e;
		if(p[i].a!=p[i+1].a||p[i].b!=p[i+1].b||p[i].c!=p[i+1].c||p[i].d!=p[i+1].d) {
			s[++tot]={p[i].a,p[i].b,p[i].c,p[i].d,sum,0,tot};
			sum=false;
		}
	}
	rep(i,1,n) tr[i]=-1000100000000000;
	n=tot;
	rep(i,1,n) f[i]=s[i].e;
	cdq(1,n);
	rep(i,1,n) ans=max(ans,f[i]);
	printf("%lld",ans);
	return;
}
fire main() {
	T=1; 
	while(T--) {
		solve();
	}
	return false;
}

posted @ 2024-03-18 18:42  highkj  阅读(20)  评论(0)    收藏  举报