• [SDOI2011]拦截导弹


    IV.I.[SDOI2011]拦截导弹

    我当初为什么要用CDQ分治而不是树套树开这题……

    明显三维偏序。然后一个点的可能性就是前缀路径数乘以后缀路径数除以总路径数。

    CDQ分治有一大坨的细节需要处理!

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long double ld;
    int n,m;
    struct tad{
    	int len;
    	ld ways;
    	tad(){len=0,ways=0;}
    	tad(int L,ld W){len=L,ways=W;}
    	friend tad operator+(const tad&u,const tad&v){
    		tad w;
    		w.len=max(u.len,v.len);
    		if(w.len==u.len)w.ways+=u.ways;
    		if(w.len==v.len)w.ways+=v.ways;
    		return w;
    	}
    }t[50100],res;
    void ADD(int x,tad y){while(x)t[x]=t[x]+y,x-=x&-x;}
    tad SUM(int x){tad ret;while(x<=m)ret=ret+t[x],x+=x&-x;ret.len++;return ret;}
    void ERA(int x){while(x)t[x]=tad(),x-=x&-x;}
    struct dat{int x,y,z;}p[50100],q[50100];
    bool cmp1(dat&u,dat&v){return u.x<v.x;}
    bool cmp2(dat&u,dat&v){return u.y>v.y;}
    void CDQ(int l,int r,tad *F){
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	CDQ(l,mid,F);
    	for(int i=l;i<=r;i++)q[i]=p[i];
    	sort(q+l,q+mid+1,cmp2),sort(q+mid+1,q+r+1,cmp2);
    	for(int i=l,j=mid+1;j<=r;j++){
    		while(i<=mid&&q[i].y>=q[j].y)ADD(q[i].z,F[q[i].x]),i++;
    		F[q[j].x]=F[q[j].x]+SUM(q[j].z);
    	}
    	for(int i=l;i<=mid;i++)ERA(q[i].z);
    	CDQ(mid+1,r,F);
    }
    vector<int>v;
    tad f[50100],g[50100];
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%d%d",&p[i].y,&p[i].z),v.push_back(p[i].z),p[i].x=i,f[i]=g[i]=tad(1,1);
    	sort(v.begin(),v.end()),v.resize(m=unique(v.begin(),v.end())-v.begin());
    	for(int i=1;i<=n;i++)p[i].z=lower_bound(v.begin(),v.end(),p[i].z)-v.begin()+1;
    	CDQ(1,n,f);
    	for(int i=1;i<=n;i++)p[i].x=n-p[i].x+1,p[i].y=-p[i].y,p[i].z=m-p[i].z+1;
    	sort(p+1,p+n+1,cmp1);
    //	for(int i=1;i<=n;i++)printf("(%d,%d,%d)",p[i].x,p[i].y,p[i].z);puts("");
    	CDQ(1,n,g);
    	reverse(g+1,g+n+1);
    	
    //	for(int i=1;i<=n;i++)printf("(%d,%Lf)",f[i].len,f[i].ways);puts("");
    //	for(int i=1;i<=n;i++)printf("(%d,%Lf)",g[i].len,g[i].ways);puts("");
    	
    	for(int i=1;i<=n;i++)res=res+f[i];
    	printf("%d\n",res.len);
    	for(int i=1;i<=n;i++)if(f[i].len+g[i].len-1==res.len)printf("%Lf ",f[i].ways*g[i].ways/res.ways);else printf("0 ");
    	return 0;
    }
    

  • 相关阅读:
    hdu6315 Naive Operations
    noi.ac #525 神树的权值
    JSOI2018 潜入行动
    GXOI/GZOI2019 旅行者
    Educational Codeforces Round #67
    [六省联考2017] 分手是祝愿
    NOI2014 随机数生成器
    NOI2012 随机数生成器
    USACO19JAN Redistricting
    HNOI2015 菜肴制作
  • 原文地址:https://www.cnblogs.com/Troverld/p/14620767.html
Copyright © 2020-2023  润新知