對應POJ題目:點擊打開鏈接
Time Limit: 6000MS | Memory Limit: 65536K | |
Total Submissions: 16655 | Accepted: 5203 |
Description
Your task is to help Jiajia calculate which dog ate the food after each feeding.
Input
The second line contains n integers, describe the pretty value of each dog from left to right. You should notice that the dog with lower pretty value is prettier.
Each of following m lines contain three integer i,j,k, it means that Jiajia feed the k-th pretty dog in this feeding.
You can assume that n<100001 and m<50001.
Output
Sample Input
7 2 1 5 2 6 3 7 4 1 5 3 2 7 1
Sample Output
3 2
題意:
給n個數和m個區間查詢(每個查詢區間之間可能有交集,但不會覆蓋),每個查詢輸出序列的第k小的數。
思路:
據說可用各種樹過~
伸展樹,首先保存下所有查詢,對查詢的左邊界按升序排序,然後對排序後的每個查詢區間建立一顆獨立的樹,至於第k小,就可以直接計算出來;在爲下一個查詢區間建樹時,如果跟前一次查詢區間沒有交集,就把整棵樹刪掉重新建;如果有交集,就可以把跟前一次查詢區間沒有交集的結點刪掉,有交集的留下,再把當前查詢區間沒有交集的加上。
#include <cstdio>
#include <cstdlib>
#include <string>
#include <algorithm>
#include <string.h>
#include <cmath>
#include <iostream>
#define MAX(x, y) ((x)>(y)?(x):(y))
const int MAXN = 100100;
using namespace std;
typedef int Type;
Type a[MAXN], b[MAXN>>1];
struct Q
{
int x, y, z, id;
Q()
{
id = x = y = z = 0;
}
};
Q q[MAXN>>1];
bool cmp(Q q1, Q q2)
{
if(q1.x != q2.x) return q1.x < q2.x;
else return q1.y < q2.y;
}
typedef struct TREE
{
Type val;
TREE *fa, *l, *r;
int sz; //以該結點爲根的樹的總結點數
}Tree;
Tree *mark[MAXN]; //保存結點位置
struct SplayTree
{
public:
SplayTree()
{
rt = NULL;
inf = 1000000000;
}
void Push_up(Tree *T)
{
T->sz = (T->l ? T->l->sz : 0) + (T->r ? T->r->sz : 0) + 1;
}
void NewNode(Tree *pre, Tree *&T, Type v)
{
T = (Tree *)malloc(sizeof(Tree));
T->val = v;
T->sz = 1;
T->fa = pre;
T->l = T->r = NULL;
}
void Init()
{
NewNode(NULL, rt, -inf);
NewNode(rt, rt->r, inf);
rt->sz = 2;
}
void R_rotate(Tree *x)
{
Tree *y = x->fa;
Tree *z = y->fa;
Tree *k = x->r;
y->l = k;
x->r = y;
if(z){
if(y == z->l) z->l = x;
else z->r = x;
}
if(k) k->fa = y;
y->fa = x;
x->fa = z;
Push_up(y);
}
void L_rotate(Tree *x)
{
Tree *y = x->fa;
Tree *z = y->fa;
Tree *k = x->l;
y->r = k;
x->l = y;
if(z){
if(y == z->r) z->r = x;
else z->l = x;
}
if(k) k->fa = y;
y->fa = x;
x->fa = z;
Push_up(y);
}
//尋找第x個數的結點
Tree *FindTag(int x)
{
if(NULL == rt) return NULL;
Tree *p;
p = rt;
Type sum = (p->l ? p->l->sz : 0) + 1;
while(sum != x)
{
if(sum < x){
p = p->r;
x -= sum;
}
else p = p->l;
if(NULL == p) break;
sum = (p->l ? p->l->sz : 0) + 1;
}
return p;
}
void Splay(Tree *X, Tree *&T)
{
Tree *p, *end;
end = T->fa;
while(X->fa != end)
{
p = X->fa;
if(end == p->fa){ //p是根結點
if(X == p->l) R_rotate(X);
else L_rotate(X);
break;
}
//p不是根結點
if(X == p->l){
if(p == p->fa->l){
R_rotate(p); //LL
R_rotate(X); //LL
}
else{
R_rotate(X); //RL
L_rotate(X);
}
}
else{
if(p == p->fa->r){ //RR
L_rotate(p);
L_rotate(X);
}
else{ //LR
L_rotate(X);
R_rotate(X);
}
}
}
T = X;
Push_up(T);
}
void Insert(Type *A, int x, int y)
{
int i;
//考驗指針技巧的代碼
Tree **link, *p;
for(i = x; i <= y; i++){
link = &rt;
while(*link)
{
p = *link;
if(A[i] < p->val) link = &p->l;
else link = &p->r;
}
NewNode(p, *link, A[i]);
mark[i] = *link;
Splay(*link, rt);
}
}
void Delete(Type *A, int x, int y)
{
int i;
Tree *t;
for(i = x; i <= y; i++){
t = mark[i];
Splay(t, rt);
t = rt->l;
while(t->r) t = t->r;
Splay(t, rt->l);
t = rt;
rt = rt->l;
rt->r = t->r;
free(t);
rt->r->fa = rt;
rt->fa = NULL;
Push_up(rt); //切記更新sz
}
}
void Query(int id, int x)
{
x++; //自增1,因爲有個-oo結點
Tree *p;
p = rt;
int sum = (p->l ? p->l->sz : 0) + 1;
while(sum != x)
{
if(sum < x){
p = p->r;
x -= sum;
}
else p = p->l;
if(NULL == p) break;
sum = (p->l ? p->l->sz : 0) + 1;
}
b[id] = p->val;
}
void Show()
{
InOrder(rt);
printf("\n");
}
void InOrder(Tree *T)
{
if(NULL == T) return;
InOrder(T->l);
printf("%d ", T->val);
InOrder(T->r);
}
void Free()
{
FreeTree(rt);
}
void FreeTree(Tree *T)
{
if(NULL == T) return;
FreeTree(T->l);
FreeTree(T->r);
free(T);
}
private:
Type inf;
Tree *rt;
};
SplayTree spl;
int main()
{
//freopen("in.txt","r",stdin);
int n, m, i;
while(scanf("%d%d", &n, &m) == 2)
{
for(i = 1; i <= n; i++)
scanf("%d", a + i);
for(i = 1; i <= m; i++){
scanf("%d%d%d", &q[i].x, &q[i].y, &q[i].z);
q[i].id = i; //把位置記下方便輸出
}
sort(q + 1, q + m + 1, cmp);
for(i = 1; i <= m; i++){
if(q[i].x <= q[i-1].y){ //有交集
spl.Delete(a, q[i-1].x, q[i].x - 1);
spl.Insert(a, q[i-1].y + 1, q[i].y);
}
else{
spl.Free(); //把整棵樹刪掉
spl.Init();
spl.Insert(a, q[i].x, q[i].y);
}
spl.Query(q[i].id, q[i].z);
}
spl.Free();
for(i = 1; i <= m; i++)
printf("%d\n", b[i]);
}
return 0;
}