zoukankan      html  css  js  c++  java
  • cdqz2017-test10-rehearsal(CDQ分治&可持久化线段树&单调栈)

    题意:

    给出n个三元组 e[i]=(si,ti,wi)

    第i个三元组的价值为 Σ w[j] ,j 满足以下4个条件:

    1、j<i

    2、tj<ti

    3、sj<si

    4、不存在j<k<i,且sj<sk<si

    把每个三元组看作二维平面上的一个点(i,si)

    先不考虑t,

    那么j若满足要求,必须满足以(j,sj)为左下角,以(i,si)为右上角的矩形内没有其他的三元组

    可以用CDQ分治解决

    设三元组e[i]的坐标为(x,y)=(i,si)

    先将所有的三元组按s排序,然后按x归并

    即左右两边归并时,左边所有三元组的y小于右边所有三元组的s

    归并结束后,左右两边合并为x递增的集合

    考虑左边对右边的贡献

    在归并的过程中维护两个单调栈l和r

    栈l 维护左边的三元组,满足x单调递增,y单调递减

    栈r 维护右边的三元组,满足x单调递增,y单调递增,且栈顶的y一定小于当前的y

    对于右边的一个三元组j,左边对其有贡献的三元组i满足

    1、i<j,因为是按x归并,所以此条件一定满足

    2、i在栈l中,如果i不在栈l中,说明i后面,j前面存在一个k,满足si<sk<sj

    3、设栈r的栈顶为k,i>k,否则这个k会使 i<k<j 且si<sk<sj

    我们只维护栈l中三元组的信息,即可满足条件2

    至于条件3,因为栈l的x单调递增,二分查找第一个满足条件的,那么它到栈l的栈顶都满足条件

    记录栈l中w的前缀和即可解决

    现在再考虑t,只需要将前缀和改为可持久化权值线段树即可

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    #define N 50001
    
    int n;
    struct node
    {
        int s,t,w;
        int id;
        int ans;
    }e[N],g[N],stl[N],str[N];
    
    int has[N];
    
    bool cmpy(node p,node q)
    {
        return p.s<q.s;
    }
    
    bool cmpx(node p,node q)
    {
        return p.id<q.id;
    }
    
    namespace Segment
    {
        int tot,rt_id;
        int root[N];
        
        int sum[N*16],lc[N*16],rc[N*16];
        
        void pre()
        {
            tot=rt_id=0;
        }
        
        int query(int x,int y,int l,int r,int opr)
        {
            if(r<=opr) return sum[y]-sum[x];
            int mid=l+r>>1;
            int res=query(lc[x],lc[y],l,mid,opr);
            if(opr>mid) res+=query(rc[x],rc[y],mid+1,r,opr);
            return res;  
        }
        
        int insert(int x,int l,int r,int pos,int w)
        {
            int num=++tot;
            sum[num]=sum[x];
            lc[num]=lc[x];
            rc[num]=rc[x];
            sum[num]+=w;
            if(l==r) return num;
            int mid=l+r>>1;
            if(pos<=mid) lc[num]=insert(lc[x],l,mid,pos,w);
            else rc[num]=insert(rc[x],mid+1,r,pos,w);
            return num;
        }
        
        int get(int L,int R,int lim)
        {
            if(L>R || !lim) return 0;
            return query(root[L-1],root[R],1,n,lim);
        }
        
        void del()
        {
            tot=root[rt_id]-1;
            rt_id--;
        }
        
        void add(int pos,int w)
        {
            rt_id++;
            root[rt_id]=insert(root[rt_id-1],1,n,pos,w);
        }
    };
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    void init()
    {
        read(n);
        for(int i=1;i<=n;++i)
        {
            read(e[i].s); read(e[i].t); read(e[i].w);
            e[i].id=i;
        }
        for(int i=1;i<=n;++i) has[i]=e[i].s;
        sort(has+1,has+n+1);
        for(int i=1;i<=n;++i) e[i].s=lower_bound(has+1,has+n+1,e[i].s)-has;
        for(int i=1;i<=n;++i) has[i]=e[i].t;
        sort(has+1,has+n+1);
        for(int i=1;i<=n;++i) e[i].t=lower_bound(has+1,has+n+1,e[i].t)-has;
    }
    
    void solve(int l,int r)
    {
        if(l==r) return;
        int mid=l+r>>1;
        solve(l,mid);
        solve(mid+1,r);
        int topl=0,topr=0;
        int i=l,j=mid+1,tmp=l;
        Segment::pre();
        while(i<=mid || j<=r)
        {
            if(j<=r && ( i>mid || e[j].id<e[i].id))
            {
                while(topr && str[topr].s>e[j].s) topr--;
                int pos=lower_bound(stl+1,stl+topl+1,str[topr],cmpx)-stl;
                e[j].ans+=Segment::get(pos,Segment::rt_id,e[j].t-1);
                str[++topr]=e[j];
                g[tmp++]=e[j++];
            }
            else
            {
                while(topl && stl[topl].s<e[i].s) 
                {
                    Segment::del();
                    topl--;
                }
                Segment::add(e[i].t,e[i].w);
                stl[++topl]=e[i];
                g[tmp++]=e[i++];
            }
        }
        for(int k=l;k<=r;++k) e[k]=g[k];
    }
    
    int main()
    {
        freopen("rehearsal.in","r",stdin);
        freopen("rehearsal.out","w",stdout);
        init();
        sort(e+1,e+n+1,cmpy);
        solve(1,n);
        sort(e+1,e+n+1,cmpx);
        for(int i=1;i<=n;++i) printf("%d
    ",e[i].ans); 
    }
  • 相关阅读:
    C++ 并发编程 01 线程api
    C# CS1591 缺少对公共可见类型或成员的 XML 注释 问题解决
    Web Api HelpPage
    C++11新特性介绍 02
    C++11新特性介绍 01
    Autofac框架详解
    Linux gdb调试器用法全面解析
    BCM_SDK命令
    VLAN
    java_Observer Design Pattern
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8718239.html
Copyright © 2011-2022 走看看