• LOJ#2585. 「APIO2018」新家 线段树二分+堆


    自己想出来的,还是相当开心的(说实话这题也不难 QAQ......)  

    首先,那个时间限制非常好处理:离线然后拆成插入和删除就行.

    对于每一种元素的每一个位置维护一个 $pre_{i}$ 表示上一次出现的位置.

    假设我们查询的位置是 $pos$,我们二分答案 $mid$.

    如果 $mid$ 合法,就要有 $x_{i} > pos+mid$ 且 $pre_{i}<pos-mid$.

    显然,如果全扫一遍每一种元素的话显然会 TLE.

    考虑维护以 $x_{i}$ 为下标,$pre_{i}$ 为权值的线段树.

    对于每一个区间,维护其最小值(这个用 set 或可删除堆实现)

    然后在线段树上二分就行了,判断 $mid$ 是否合法的话就是看右区间的堆顶是否合法.

    只在叶节点开 multiset 就行了,时间复杂度是一个 log 的.    

    code: 

    #include <set>  
    #include <ctime> 
    #include <cstdio> 
    #include <vector>  
    #include <cstring> 
    #include <algorithm>  
    #define ll long long     
    #define N 300008   
    #define pb push_back 
    #define lson now<<1  
    #define rson now<<1|1   
    #define inf 1500000000   
    #define setIO(s) freopen(s".in","r",stdin)  , freopen(s".out","w",stdout)  
    using namespace std;   
    int A[N<<1],Ans[N];        
    int n,K,Q,inf1,inf2; 
    struct data 
    {
        int op,t,ty,x;          
        data(int op=0,int t=0,int ty=0,int x=0):op(op),t(t),ty(ty),x(x){}        
        bool operator<(const data b) const { return t<b.t; }   
    };     
    vector<data>g;   
    struct ques
    {
        int x,t,id;    
        ques(int x=0,int t=0,int id=0):x(x),t(t),id(id){}   
        bool operator<(const ques b) const { return t<b.t; }
    }arr[N];                   
    int minv[N<<4];  
    multiset<int>col[N];  
    multiset<int>se[N<<4];   
    multiset<int>::iterator it;  
    inline int minn(int x) { return se[x].size()?*se[x].begin():inf;  }          
    void update(int l,int r,int now,int p,int v,int op) 
    {      
        if(l==r) 
        {
            if(op==1) se[now].insert(v);  
            else se[now].erase(se[now].lower_bound(v));   
            minv[now]=minn(now);  
            return;  
        }
        int mid=(l+r)>>1;   
        if(p<=mid)  update(l,mid,lson,p,v,op);   
        else update(mid+1,r,rson,p,v,op);      
        minv[now]=min(minv[lson],minv[rson]);                             
    }
    int query(int l,int r,int now,int key) 
    { 
        if(l==r) return min(A[l]-key,key-minv[now]);    
        int mid=(l+r)>>1;      
        if(A[mid]-key<key-minv[rson]) return max(A[mid]-key,query(mid+1,r,rson,key));  
        else return max(key-minv[rson],query(l,mid,lson,key));              
    }             
    int ask(int l,int r,int now,int p) 
    {
        if(l==r) return minv[now];  
        int mid=(l+r)>>1;  
        if(p<=mid) return ask(l,mid,lson,p);  
        else return ask(mid+1,r,rson,p);  
    } 
    void build(int l,int r,int now) 
    {
        minv[now]=inf;   
        if(l==r) return; 
        int mid=(l+r)>>1;  
        build(l,mid,lson),build(mid+1,r,rson);  
    }
    char *p1,*p2,buf[100000];   
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)    
    int rd() 
    {
        int x=0; char c;   
        while(c<48) c=nc();   
        while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc();   
        return x;  
    }
    int main() 
    { 
        // setIO("input");          
        int cn=0;   
        n=rd(),K=rd(),Q=rd();  
        A[++cn]=inf,A[++cn]=-inf;  
        for(int i=1;i<=n;++i) 
        {
            int x=rd(),t=rd(),a=rd(),b=rd();     
            g.pb(data(1,a,t,x)),g.pb(data(-1,b+1,t,x)),A[++cn]=x;   
        }  
        for(int i=1;i<=Q;++i) 
            arr[i].x=rd(),arr[i].t=rd(),arr[i].id=i,A[++cn]=arr[i].x;                                 
        sort(A+1,A+1+cn);   
        cn=unique(A+1,A+1+cn)-A-1;      
        for(int i=1;i<=Q;++i)       arr[i].x=lower_bound(A+1,A+1+cn,arr[i].x)-A; 
        for(int i=0;i<g.size();++i) g[i].x=lower_bound(A+1,A+1+cn,g[i].x)-A;    
        sort(arr+1,arr+1+Q); 
        sort(g.begin(),g.end());        
        inf1=lower_bound(A+1,A+1+cn,-inf)-A;   
        inf2=lower_bound(A+1,A+1+cn,inf)-A;               
        for(int i=1;i<=K;++i) col[i].insert(inf1),col[i].insert(inf2);     
        build(1,cn,1);  
        for(int i=1;i<=K;++i) update(1,cn,1,inf2,-inf,1);       
        for(int i=1,j=0;i<=Q;++i) 
        {
            for(;j<g.size()&&g[j].t<=arr[i].t;++j)                
            {              
                if(g[j].op==-1) 
                {
                    int c=g[j].ty,pos=g[j].x,pr,nx;  
                    it=col[c].lower_bound(pos);    
                    it--,pr=(*it);     
                    it++,it++,nx=(*it);  
                    update(1,cn,1,pos,A[pr],-1);    
                    update(1,cn,1,nx,A[pos],-1);    
                    update(1,cn,1,nx,A[pr],1);   
                    col[c].erase(col[c].lower_bound(pos));    
                } 
                else 
                {       
                    int c=g[j].ty,pos=g[j].x,pr,nx;   
                    col[c].insert(pos);    
                    it=col[c].lower_bound(pos);    
                    it--,pr=(*it);   
                    it++,it++,nx=(*it);    
                    update(1,cn,1,nx,A[pr],-1);     
                    update(1,cn,1,pos,A[pr],1);  
                    update(1,cn,1,nx,A[pos],1);    
                }
            }     
            Ans[arr[i].id]=(ask(1,cn,1,inf2)==-inf?-1:query(1,cn,1,A[arr[i].x]));     
        }   
        for(int i=1;i<=Q;++i) printf("%d
    ",Ans[i]); 
        return 0; 
    }
    

      

  • 相关阅读:
    回文串---最长回文
    回文串---Hotaru's problem
    回文串--- Girls' research
    回文串---吉哥系列故事——完美队形II
    回文串---Palindrome
    treap树---营业额统计
    treap树---Double Queue
    《程序员代码面试指南》第二章 链表问题 复制含有随机指针节点的链表
    《程序员代码面试指南》第二章 链表问题 将单链表按某值划分为左边小,中间相等,右边大的链表
    《程序员代码面试指南》第二章 链表问题 反转部分单向链表
  • 原文地址:https://www.cnblogs.com/guangheli/p/13032203.html
Copyright © 2020-2023  润新知