hdu 4006 The kth great number 很複雜的線段樹,至少對於我來說,但也學會了很多!!!!!!!!!!
阿新 • • 發佈:2019-02-19
這道題是網路預選賽上做的,當時就是超時,後來知道是線段樹,從時間複雜度來說用線段樹先是將所用的點記錄然後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; }