• BZOJ 4369: [IOI2015]teams分组 单调栈+主席树


    这个题的思路还是十分巧妙的. 

    我们发现我们要查询的区域恰好构成了一个梯形.  

    然后用那个单调栈去维护折线,并用主席树做二维数点. 

    code:

    #include <cstdio> 
    #include <algorithm> 
    #include <stack>  
    #include <cstring> 
    #include <vector>  
    #define N 500009    
    #define lson s[x].ls
    #define rson s[x].rs    
    #define ll long long 
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;    
    int n,tot,tmp;   
    int rt[N],sor[N],id[N];  
    struct data 
    {
        int l,r,id;  
        data(int l=0,int r=0,int id=0):l(l),r(r),id(id){}      
    }A[N<<1],up[N<<1];       
    bool cmp(data a,data b) 
    {
        return a.r==b.r?(a.id==b.id?a.l<b.l:a.id<b.id):a.r<b.r;                
    }
    bool cmp2(data a,data b) { return a.l<b.l; }  
    namespace presist 
    {
        struct node 
        {  
            int ls,rs,sum;     
        }s[N*70];    
        int newnode() { return ++tot; }   
        void build(int &x,int l,int r) 
        {
            x=newnode();  
            if(l==r) return;  
            int mid=(l+r)>>1;   
            build(lson,l,mid),build(rson,mid+1,r);    
        }
        int update(int x,int l,int r,int p,int v) 
        {
            int now=newnode();  
            s[now]=s[x],s[now].sum=s[x].sum+v;   
            if(l==r) return now;   
            int mid=(l+r)>>1;    
            if(p<=mid) s[now].ls=update(lson,l,mid,p,v);   
            else s[now].rs=update(rson,mid+1,r,p,v);    
            return now;     
        }
        int query(int x,int l,int r,int L,int R)
        {
            if(!x||L>R) return 0;   
            if(l>=L&&r<=R) return s[x].sum;  
            int mid=(l+r)>>1,re=0;   
            if(L<=mid)  re+=query(lson,l,mid,L,R);   
            if(R>mid)   re+=query(rson,mid+1,r,L,R);   
            return re;   
        }
        int get(int x,int y,int l,int r,int re) 
        {
            if(l==r) return l;    
            int mid=(l+r)>>1,p=s[s[x].ls].sum-s[s[y].ls].sum;  
            if(p>=re) return get(s[x].ls,s[y].ls,l,mid,re);  
            else return get(s[x].rs,s[y].rs,mid+1,r,re-p);   
        }
    };         
    struct sta
    {    
        int h,r;   
        sta(int h=0,int r=0):h(h),r(r){}  
    };   
    stack<sta>S;   
    void solve() 
    {
        int i,j,m,sn=0;  
        scanf("%d",&m);  
        for(i=1;i<=m;++i) scanf("%d",&sor[i]),sn+=sor[i]; 
        if(sn>n) { printf("0
    "); return; }   
        sort(sor+1,sor+1+m);   
        while(!S.empty()) S.pop();  
        S.push(sta(tmp,0));         
        for(i=1;i<=m;++i) 
        {    
            int cur=id[sor[i]],remain=sor[i];  
            while(!S.empty()&&S.top().h<cur) S.pop();   
            while(remain&&!S.empty()) 
            {          
                int det=presist::query(rt[sor[i]],1,tmp,cur+1,S.top().h)-presist::query(rt[S.top().r],1,tmp,cur+1,S.top().h);
                if(det>=remain) 
                {     
                    int c=presist::query(rt[sor[i]],1,tmp,1,cur)-presist::query(rt[S.top().r],1,tmp,1,cur);        
                    cur=presist::get(rt[sor[i]],rt[S.top().r],1,tmp,remain+c);   
                    remain=0;    
                    break;   
                }             
                else 
                {
                    remain-=det;  
                    cur=S.top().h;     
                    S.pop();    
                }
            }
            if(S.empty()) { printf("0
    "); return; }
            S.push(sta(cur,sor[i]));                          
        }
        printf("1
    ");    
    }
    int main() 
    {
        // setIO("input");                        
        int i,j,Q,cn=0;   
        scanf("%d",&n),tmp=n;   
        for(i=1;i<=n;++i) scanf("%d%d",&A[i].l,&A[i].r),A[i].id=1;  
        for(i=1;i<=n;++i) A[++tmp].l=0,A[tmp].r=i,A[tmp].id=-1;                   
        sort(A+1,A+1+tmp,cmp);   
        for(i=1;i<=tmp;++i) 
        {   
            if(A[i].id==-1)  id[A[i].r]=i; 
            else A[i].r=i,up[++cn]=A[i]; 
        }
        sort(up+1,up+1+n,cmp2),tmp+=2;                
        presist::build(rt[0],1,tmp);   
        for(j=i=1;i<=n;++i)   
        {
            rt[i]=rt[i-1];    
            while(j<=n&&up[j].l==i)                
                rt[i]=presist::update(rt[i],1,tmp,up[j].r,1),++j;    
        }            
        scanf("%d",&Q);  
        for(i=1;i<=Q;++i) solve();    
        return 0;
    }    
    

      

  • 相关阅读:
    linux常用命令(持续更新)
    nginx和redis
    网络编程BIO、NIO、AIO
    同步和异步、阻塞和非阻塞
    执行一条sql语句过程
    InnoDB 的B+树索引原理
    InnoDB 为啥要选择B+树来存储数据
    MySQL数据库引擎简介
    java并发编程(同步、同步容器、线程池)
    putty登录linux遭refuse
  • 原文地址:https://www.cnblogs.com/guangheli/p/12268924.html
Copyright © 2020-2023  润新知