<题目链接>
题目大意:
进行两种操作: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)); } } }