这道题是网络预选赛上做的,当时就是超时,后来知道是线段树,从时间复杂度来说用线段树先是将所用的点记录然后nlog的快排,之后查询就是logn了,软和不用线段树,之后的查询是On的复杂度,要是来一堆大数据那就必然超时了
废话不多说了,先将记录的所用点排序,在离散化,建树,将数据记录在最低叶上,再用num记录区间内点的数量,在从后往前搜,遇见I就将对应点之前的区间num减1,遇见Q就搜索K大的数!!!!!!!!!!
#include<iostream> using namespace std; #include<algorithm> int size; struct operaten//定义操作数 { char cha; int num; }ope[1000010]; int num[1000010]; int ans[1000010]; int po; struct Curnode//当前节点 { int big; int bnum; }curnode[1000010]; struct node//定义树 { int ll; int rr; int big; int bnum; }a[3000010]; void init(int n)//离散化 { size=1; curnode[size].big=num[1]; curnode[size].bnum=1; for(int i=2;i<=n;i++) { if(num[i]==curnode[size].big) { curnode[size].bnum++; } else { curnode[++size].big=num[i]; curnode[size].bnum=1; } } return ; } void build(int left,int right,int p)//建树 { a[p].ll=left;// 两个子叶表示区间 a[p].rr=right;// if(left==right) { a[p].big=curnode[left].big; a[p].bnum=curnode[left].bnum; return ; } int mid=(left+right)/2; build(left,mid,2*p); build(mid+1,right,2*p+1);//有规矩,这里的mid必须加一 ,注意得到mid的除法模式 a[p].bnum=a[p*2].bnum+a[p*2+1].bnum; a[p].big=-1; return ; } void updata(int delnum,int p) { a[p].bnum--; if(a[p].ll==a[p].rr) return; int mid=(a[p].ll+a[p].rr)/2; if(curnode[mid].big>=delnum)//注意啊!!涉及到这个等号都要向左面 { updata(delnum,p*2); } else updata(delnum,p*2+1); return ; } void query(int k,int p) { if(a[p].ll==a[p].rr) { ans[po++]=curnode[a[p].ll].big; return ; } if(a[p*2+1].bnum>=k) { query(k,p*2+1); } else query(k-a[p*2+1].bnum,p*2); return ; } int main() { int n,k; char ch; int temp; while(scanf("%d%d",&n,&k)!=EOF) { po=1; int t=1; for(int i=1;i<=n;i++) { getchar(); scanf("%c",&ch); if(ch=='I') { scanf("%d",&temp); ope[i].num=temp; ope[i].cha='I'; num[t++]=temp; } else { ope[i].num=-1; ope[i].cha='Q'; } } sort(num+1,num+t); init(t-1); build(1,size,1); for(int i=n;i>=1;i--) { if(ope[i].cha=='I') { updata(ope[i].num,1); } if(ope[i].cha=='Q') { query(k,1); } } for(int i=po-1;i>=1;i--) printf("%d\n",ans[i]); } return 0; }