zoukankan      html  css  js  c++  java
  • [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;
    }
    

  • 相关阅读:
    JS字符串去重
    svn回退到某一版本
    WebStorm格式化代码4个空格设置
    DevExpress中 的DataGrid每一行根据其类型显示控件的种类
    各大系统刷新DNS缓存方法
    Kali Linux中前十名的Wifi攻击工具
    CentOS远程执行漏洞
    判断是否移动端的几种方法
    笔记
    Linux常用命令
  • 原文地址:https://www.cnblogs.com/Troverld/p/14620824.html
Copyright © 2011-2022 走看看