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]\) 中。
同时,有一些需要注意的地方:
-
CDQ分治时不能乱动数组,排序后要么复原,要么额外拷贝一份排序。
-
排序时,比如我们以排第三维为例,光按第三维排不够,要继续按第四维,然后是一维、二维排。
-
注意相同的元素,以及答案是负数的情形。
可能会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;
}