• Gym 102091K The Stream of Corning 2 (线段树+离线)


    <题目链接>

    题目大意:

    进行两种操作:1.给定一个数的出现时间、价值、消失时间;

           2.进行一次询问,问你当前时间,第K大的数的价值。

    解题分析:

    采用离线集中处理,将每个数的出现时间和它的消失时间分组存下,并且存下所有的询问。然后就是依次进行所有询问,将这些询问时间点之前的点插入,将已经消失的点删除。因为算了一下复杂度感觉能过,所以就没有用离散化,线段树的代表区间大小就是1~1e6,线段树的节点维护的信息就是这个节点所对应区间的有效节点个数。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e5+5 , MAX = 1e6+5;
    
    #define lson rt<<1,l,mid
    #define rson rt<<1|1,mid+1,r
    struct Node{
        int time,val;
        Node (int _time=0,int _val=0):time(_time),val(_val){}
        bool operator < (const Node & tmp) const { return time<tmp.time; }
    }node1[N],node2[N],d[N];
    
    int tr[MAX<<2];
    
    template<typename T>
    inline void read(T&x){
        x=0;int f=1;char ch=getchar();
        while(ch<'0' ||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); }
        while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
        x*=f;
    }
    
    inline void Pushup(int rt){ tr[rt]=tr[rt<<1]+tr[rt<<1|1]; }
    void update(int rt,int l,int r,int loc,int val){
        if(l==r){ tr[rt]+=val;return; }
        int mid=l+r>>1;
        if(loc<=mid)update(lson,loc,val);
        if(loc>mid)update(rson,loc,val);
        Pushup(rt);
    }
    int query(int rt,int l,int r,int k){
        if(l==r)return l;
        int mid=l+r>>1;
        if(tr[rt<<1]>=k)return query(lson,k);
        else if(tr[rt<<1]<k)return query(rson,k-tr[rt<<1]);    //左子树不够k个,则第k个一定在右子树
    }
    int main(){
        int T,ncase=0;scanf("%d",&T);
        while(T--){
            printf("Case %d:
    ",++ncase);
            int q;scanf("%d",&q);
            int cnt1=0,cnt2=0,cnt3=0;
            while(q--){
                int op;read(op);
                if(op==1){
                    int s,e,w;read(s);read(w);read(e);
                    cnt1++,cnt2++;
                    node1[cnt1]=Node(s,w);     //node1记录开始时间
                    node2[cnt2]=Node(e,w);     //node2记录结束时间
                }else {
                    int now,k;read(now),read(k);
                    cnt3++;
                    d[cnt3].time=now,d[cnt3].val=k;     //记录下询问数组
                }
            }
            sort(node1+1,node1+1+cnt1);sort(node2+1,node2+1+cnt2); sort(d+1,d+1+cnt3);   
            int p1=1,p2=1;    //遍历‘建立’和‘删除’这两个数组的指针
            memset(tr,0,sizeof(tr));     //建树
            for(int i=1;i<=cnt3;i++){
                int now=d[i].time,k=d[i].val;
                while(p1<=cnt1 && node1[p1].time<=now){   //将当前时间前存活的的点插入线段树
                    update(1,1,MAX,node1[p1].val,1);
                    p1++;
                }
                while(p2<=cnt2 && node2[p2].time<now){    //将当前时间前死亡的点删除线段树
                    update(1,1,MAX,node2[p2].val,-1);
                    p2++;
                }
                if(tr[1]<k){ puts("-1");continue; }    //如果不足k个存活,直接输出-1
                printf("%d
    ",query(1,1,MAX,k));
            }
        }
    }
  • 相关阅读:
    《认知突围》摘抄
    《java多线程编程核心技术》----ThreadLocal
    java有必要记录的东西
    spring源码几个servlet功能的介绍
    基于openapi3.0的yaml文件生成java代码的一次实践
    Android攻城狮 调试
    Android攻城狮 http协议
    Android攻城狮 Android中更新UI的几种方式
    Android攻城狮 Handler与子线程
    Android攻城狮Handler简介
  • 原文地址:https://www.cnblogs.com/00isok/p/10514081.html
Copyright © 2020-2023  润新知