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

IV.V.[DBOI2019]德丽莎世界第一可爱

事四维偏序模板

二维偏序我们用BIT,三维偏序我们用CDQ套BIT,四维偏序,可以CDQ套树套树CDQ套BIT。

什么意思?

我们排序排掉第一维。

然后,在第二维上CDQ:当我们要计算 \([l,mid]\)\([mid+1,r]\) 的贡献时,发现其有如下几条限制:

贡献的物品来自 \([l,mid]\),收到贡献的物品来自 \([mid+1,r]\);二、三、四维满足偏序关系。

于是我们继续CDQ,只不过,在内层的CDQ时,我们只将外层CDQ中 \([l,mid]\) 中物品加入BIT,只有 \([mid+1,r]\) 中物品能从BIT更新。

这就意味着我们得在每个物品额外打上一个标记,用来表示其是否在 \([l,mid]\) 中。

同时,有一些需要注意的地方:

  1. CDQ分治时不能乱动数组,排序后要么复原,要么额外拷贝一份排序。

  2. 排序时,比如我们以排第三维为例,光按第三维排不够,要继续按第四维,然后是一维、二维排。

  3. 注意相同的元素,以及答案是负数的情形。

可能会debug很久很久

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=0xc0c0c0c0c0c0c0c0;
int n,m;
ll res=inf,f[50100];
struct node{
	ll a,b,c,d,e;
	int id;
	bool fir;
	node(){}
	node(ll A,ll B,ll C,ll D){a=A,b=B,c=C,d=D;}
	friend bool operator==(const node&u,const node&v){return u.a==v.a&&u.b==v.b&&u.c==v.c&&u.d==v.d;}
	void print(){printf("(%d,%d,%d,%d,%d):%d-%d\n",a,b,c,d,e,f[id],fir);}
}p[50100],q[50100],o[50100];
bool cmpa(node&x,node&y){
	if(x.a!=y.a)return x.a<y.a;
	if(x.b!=y.b)return x.b<y.b;
	if(x.c!=y.c)return x.c<y.c;
	if(x.d!=y.d)return x.d<y.d;
	return x.e>y.e;
}
bool cmpb(node&x,node&y){
	if(x.b!=y.b)return x.b<y.b;
	if(x.c!=y.c)return x.c<y.c;
	if(x.d!=y.d)return x.d<y.d;
	return x.a<y.a;
}
bool cmpc(node&x,node&y){
	if(x.c!=y.c)return x.c<y.c;
	if(x.d!=y.d)return x.d<y.d;
	if(x.a!=y.a)return x.a<y.a;
	return x.b<y.b;
}
vector<int>v;
ll t[50100];
void ADD(int x,ll y){while(x<=m)t[x]=max(t[x],y),x+=x&-x;}
ll SUM(int x){ll ret=inf;while(x)ret=max(ret,t[x]),x-=x&-x;return ret;}
void ERA(int x){while(x<=m)t[x]=inf,x+=x&-x;}
void CDQ2(int l,int r){
//	printf("2:[%d,%d]\n",l,r);
	if(l==r)return;
	int mid=(l+r)>>1;
	CDQ2(l,mid);
	for(int i=l;i<=r;i++)q[i]=o[i];
	sort(q+l,q+mid+1,cmpc),sort(q+mid+1,q+r+1,cmpc);
//	printf("C:");for(int i=l;i<=r;i++)printf("%d ",q[i].id);puts("");
	for(int i=l,j=mid+1;j<=r;j++){
		for(;i<=mid&&q[i].c<=q[j].c;i++)if(q[i].fir)ADD(q[i].d,f[q[i].id]);
		if(!q[j].fir)f[q[j].id]=max(f[q[j].id],q[j].e+SUM(q[j].d));
	}
	for(int i=l;i<=mid;i++)if(q[i].fir)ERA(q[i].d);
	CDQ2(mid+1,r);
}
void CDQ1(int l,int r){
//	printf("1:[%d,%d]\n",l,r);
	if(l==r){res=max(res,f[p[l].id]);return;}
	int mid=(l+r)>>1;
	CDQ1(l,mid);
	for(int i=l;i<=r;i++)o[i]=p[i];
	for(int i=l;i<=mid;i++)o[i].fir=true;
	sort(o+l,o+r+1,cmpb);
//	printf("B:");for(int i=l;i<=r;i++)printf("%d ",o[i].id);puts("");
	CDQ2(l,r);
	CDQ1(mid+1,r);
}
int main(){
	scanf("%d",&m);
	for(int i=1;i<=m;i++)scanf("%lld%lld%lld%lld%lld",&p[i].a,&p[i].b,&p[i].c,&p[i].d,&p[i].e),v.push_back(p[i].d);
	sort(p+1,p+m+1,cmpa),n=1;
	for(int i=2;i<=m;i++)if(p[n]==p[i])p[n].e+=max(p[i].e,0ll);else p[++n]=p[i];
	sort(v.begin(),v.end()),v.resize(m=unique(v.begin(),v.end())-v.begin());
	for(int i=1;i<=n;i++)p[i].id=i,f[i]=p[i].e,p[i].fir=false,p[i].d=lower_bound(v.begin(),v.end(),p[i].d)-v.begin()+1;
	memset(t,0xc0,sizeof(t));
//	for(int i=1;i<=n;i++)p[i].print();
//	printf("A:");for(int i=1;i<=n;i++)printf("%d ",p[i].id);puts("");
	CDQ1(1,n);
	printf("%lld\n",res);
	return 0;
}

原文地址:https://www.cnblogs.com/Troverld/p/14620824.html