P2487 [SDOI2011]拦截导弹 线段树 cdq分治

  

如果他仅仅只是求最长二维非升序列长度   那么就是一个cdq模板题    dp一下即可

但是这题不仅要求dp  还要求dp的方案个数

所以用线段树来维护  区间最大值和区间最大值的个数

初始化的话build一次更快  (当maxx[pos]==0时不继续递归即可) 

 f2 g2 为反向

那么当    

f1[i]+f2[i]-1!=maxxans  显然该元素不在任何最长子序列中
否则的话  答案为  所在方案的个数/总的方案个数  g1[i]*g2[i]/sum
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
/////////////////////////////////////
const int N=1e6+10;
ll maxx[N<<2];
double t[N<<2];
int n,m,anss[N],f1[N],f2[N],xx[N],yy[N];
double g1[N],g2[N];
void build(int l,int r,int pos)
{
    if(!maxx[pos])return ;//这条加速非常重要
    maxx[pos]=t[pos]=0;
    if(l==r){maxx[pos]=t[pos]=0;return ;}
    int m=(l+r)>>1;maxx[pos]=t[pos]=0;
    build(l,m,pos<<1);build(m+1,r,pos<<1|1);
}
void up(int pos)
{
    if(maxx[pos<<1]<maxx[pos<<1|1])
    maxx[pos]=maxx[pos<<1|1],t[pos]=t[pos<<1|1];
    else if(maxx[pos<<1]>maxx[pos<<1|1])
    maxx[pos]=maxx[pos<<1],t[pos]=t[pos<<1];
    else maxx[pos]=maxx[pos<<1],t[pos]=t[pos<<1]+t[pos<<1|1];
}
void upnode(int x,int v,double v2,int l,int r,int pos)
{
    if(l==r)
    {
        if(v==maxx[pos])t[pos]+=v2;
        else if(v>maxx[pos])maxx[pos]=v,t[pos]=v2;
        return ;
    }
    int m=(l+r)>>1;
    if(x<=m)upnode(x,v,v2,l,m,pos<<1);
    else upnode(x,v,v2,m+1,r,pos<<1|1);
    up(pos);
}
ll qmax(int L,int R,int l,int r,int pos)
{
    if(L<=l&&r<=R)return maxx[pos];
    ll ans=0;int m=(l+r)>>1;
    if(L<=m)ans=max(ans,qmax(L,R,l,m,pos<<1));
    if(R>m)ans=max(ans,qmax(L,R,m+1,r,pos<<1|1));
    return ans;
}
double qnum(int L,int R,ll v,int l,int r,int pos)
{  
    if(L<=l&&r<=R){if(maxx[pos]==v)return t[pos];return 0; }
    int m=(l+r)>>1;double ans=0;
    if(L<=m)ans+=qnum(L,R,v,l,m,pos<<1);
    if(R>m)ans+=qnum(L,R,v,m+1,r,pos<<1|1);
    return ans;
}
struct node{int x,y,id;}s[N],temp[N];
bool cmp(node a,node b){return a.x<b.x;}

void cdq1(int l,int r)
{   
    if(l==r)return ;int mid=(l+r)>>1;
    cdq1(mid+1,r);
    rep(i,l,r)temp[i]=s[i];
    sort(temp+l,temp+mid+1,cmp);sort(temp+mid+1,temp+r+1,cmp);
    int j=mid+1;
    build(1,n,1);
    rep(i,l,mid)
    {   
        while(j<=r&&temp[j].x<=temp[i].x)upnode(temp[j].y,f1[temp[j].id],g1[temp[j].id],1,n,1),j++;
        double cn=0;
        ll t=qmax(1,temp[i].y,1,n,1);
        if(!t)continue;
        cn=qnum(1,temp[i].y,t,1,n,1);
        if(f1[temp[i].id]<t+1)f1[temp[i].id]=t+1,g1[temp[i].id]=0;
        if(f1[temp[i].id]==t+1)g1[temp[i].id]+=cn;
    }
    cdq1(l,mid);
}
void cdq2(int l,int r)
{   
    if(l==r)return ;int mid=(l+r)>>1;
    cdq2(l,mid);
    rep(i,l,r)temp[i]=s[i];
    sort(temp+l,temp+mid+1,cmp);sort(temp+mid+1,temp+r+1,cmp);
    int j=mid;
    build(1,n,1);
    repp(i,r,mid+1)
    {
        while(j>=l&&temp[j].x>=temp[i].x)upnode(temp[j].y,f2[temp[j].id],g2[temp[j].id],1,n,1),j--;
        double cn=0;
        ll t=qmax(temp[i].y,n,1,n,1);
        if(!t)continue;
        cn=qnum(temp[i].y,n,t,1,n,1);
        if(f2[temp[i].id]<t+1)f2[temp[i].id]=t+1,g2[temp[i].id]=0;
        if(f2[temp[i].id]==t+1)g2[temp[i].id]+=cn;
    }
    cdq2(mid+1,r);
}
int main()
{
    cin>>n;
    rep(i,1,n)scanf("%d%d",&s[i].x,&s[i].y),s[i].id=i,f1[i]=f2[i]=1,xx[i]=s[i].x,yy[i]=s[i].y,g1[i]=g2[i]=1;
    sort(xx+1,xx+1+n);sort(yy+1,yy+1+n);
    int nx=unique(xx+1,xx+1+n)-xx-1;
    int ny=unique(yy+1,yy+1+n)-yy-1;
    rep(i,1,n)
    s[i].x=lower_bound(xx+1,xx+1+nx,s[i].x)-xx,
    s[i].y=lower_bound(yy+1,yy+1+ny,s[i].y)-yy;
    cdq1(1,n);
    int maxxans=0;
    double sum=0;
    rep(i,1,n)maxxans=max(maxxans,f1[i]);
    cout<<maxxans<<endl;
    rep(i,1,n)
    if(f1[i]==maxxans)sum+=g1[i];
    sort(s+1,s+1+n,[](node a,node b){return a.id<b.id;});
    cdq2(1,n);
    rep(i,1,n)
    {
        if(f1[i]+f2[i]-1!=maxxans)printf("0.00000 ");
        else printf("%.5lf ",g1[i]*g2[i]/sum);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/bxd123/p/11464810.html