//TREAP求第K小數<br />//感謝JSH大牛的指點<br />//這道題之所以可以用TREAP做是因為題意中有個條件,詢問區間不會出現包含的情況,因此通過對詢問區間進行排序<br />//然後通過插入和刪除的方法,來維護區間的第K小<br />//平衡樹的話自然首選TREAP了,TREAP中比較難的就在於刪除那裡,刪除的方式是通過將要刪除的結點通過左右旋的方式,在維護LEV為堆的同時,將要刪除結點旋到葉子結點處,然後刪除<br />#include<iostream><br />#include<cstdio><br />#include<algorithm><br />#include<ctime><br />using namespace std;<br />const int MAX = 100005;<br />struct Treap<br />{<br />int data,level,num;<br />int l,r;<br />}tree[MAX];<br />int size,root;<br />void left(int &x)//注意這裡是引用<br />{<br />int p = tree[x].r;<br />tree[x].r = tree[p].l;//注意這一行與下一行的順序不能反<br />tree[p].l = x;<br />x = p;<br />tree[x].num = 1;//修改當前結點孩子個數<br /> p = tree[x].l;<br /> if (p != 0)//左旋後必須更新左子樹的資訊<br /> {<br /> tree[p].num = 1;<br /> if (tree[p].l != 0) tree[p].num += tree[tree[p].l].num;<br /> if (tree[p].r != 0) tree[p].num += tree[tree[p].r].num;<br /> tree[x].num += tree[p].num;<br /> }<br /> if(tree[x].r != 0) tree[x].num += tree[tree[x].r].num;<br />}<br />void right(int &x)<br />{<br />int p = tree[x].l;<br />tree[x].l = tree[p].r;<br />tree[p].r = x;<br />x = p;<br />tree[x].num = 1;<br />p = tree[x].r;<br />if(p != 0)<br />{<br />tree[p].num = 1;<br />if(tree[p].l != 0)tree[p].num += tree[tree[p].l].num;<br />if(tree[p].r != 0)tree[p].num += tree[tree[p].r].num;<br />tree[x].num += tree[p].num;<br />}<br />if(tree[x].l != 0)tree[x].num += tree[tree[x].l].num;<br />}<br />void insert(int &x,int data)<br />{<br />if(x == 0)<br />{<br />x = ++size;<br />tree[x].data = data;<br />tree[x].l = tree[x].r = 0;<br />tree[x].level = rand();<br />tree[x].num = 1;<br />}<br />else if(data < tree[x].data)<br />{<br />tree[x].num++;<br />insert(tree[x].l,data);<br />if(tree[x].level < tree[tree[x].l].level)right(x);<br />}<br />else<br />{<br />tree[x].num++;<br />insert(tree[x].r,data);<br />if(tree[x].level < tree[tree[x].r].level)left(x);<br />}<br />}<br />void Remove(int &x,int data)<br />{<br />if(x == 0)return;<br />if(data < tree[x].data)<br />{<br />tree[x].num--;<br />Remove(tree[x].l,data);<br />}<br />else if(data > tree[x].data)<br />{<br />tree[x].num--;<br />Remove(tree[x].r,data);<br />}<br />else<br />{<br />if(tree[x].l == 0 && tree[x].r == 0)x = 0;//此時無左右子樹,到達葉子處了,將其刪除<br />else if(tree[x].l == 0)x = tree[x].r;<br />else if(tree[x].r == 0)x = tree[x].l;<br />else<br />{<br />if(tree[tree[x].l].level > tree[tree[x].r].level)<br />{<br />right(x);//先旋轉,把要刪的結點不斷選到葉子處,然後再刪除<br />tree[x].num--;//每次旋轉後X都會是當前子樹的根<br />Remove(tree[x].r,data);<br />}<br />else<br />{<br />left(x);<br />tree[x].num--;<br />Remove(tree[x].l,data);<br />}<br />}<br />}<br />}<br />int N,M,id;<br />int A[MAX];<br />struct Query<br />{<br />int st,ed,id,k,ans;<br />}Q[MAX];<br />bool cmp1(Query a,Query b)<br />{<br />if(a.st == b.st)<br />return a.ed < b.ed;<br />return a.st < b.st;<br />}<br />bool cmp2(Query a,Query b)<br />{<br />return a.id < b.id;<br />}<br />int Search(int x,int k)<br />{<br />int p = tree[x].r;//通過減去右子樹的num來判斷當前結點排第幾位<br />int K = tree[x].num - (p != 0 ? tree[p].num : 0);<br />if(K == k)return tree[x].data;<br />else if(K > k)return Search(tree[x].l,k);<br />else return Search(tree[x].r,k - K);<br />}<br />void solve()<br />{<br />root = size = 0;<br />sort(Q+1,Q+id+1,cmp1);<br />for(int i = 1;i <= M;++i)<br />{<br />if(i != 1)<br />{<br />for(int j = Q[i-1].st;j <= min(Q[i-1].ed,Q[i].st-1);++j)<br />Remove(root,A[j]);<br />}<br />int j;<br />if(i == 1)j = Q[i].st;<br />else j = max(Q[i-1].ed + 1,Q[i].st);<br />for(;j <= Q[i].ed;++j)<br />insert(root,A[j]);<br />Q[i].ans = Search(root,Q[i].k);<br />}<br />sort(Q+1,Q+id+1,cmp2);<br />for(int i = 1;i <= M;++i)<br />printf("%d/n",Q[i].ans);<br />}<br />int main()<br />{<br />srand(time(0));<br />//freopen("in.txt","r",stdin);<br />int st,ed,k;<br />scanf("%d%d",&N,&M);<br />for(int i = 1;i <= N;++i)scanf("%d",&A[i]);<br />for(int i = 1;i <= M;++i)<br />{<br />scanf("%d%d%d",&st,&ed,&k);<br />if (st > ed)swap(st,ed);<br />Q[i].st = st;<br />Q[i].ed = ed;<br />Q[i].k = k;<br />Q[i].id = i;<br />}<br />solve();<br />}