POJ 2761 Feed the dogs (SBT+離線處理詢問)

給定n個數,m次詢問,n個數爲1--n的排列,每次詢問給出了一個區間和k,詢問在區間內爲第k小的數。


區間內第k小(大)的數可以用SBT來解決,現在m次詢問則是動態的,可以用離線處理:將詢問區間排序,每次需要插入則插入,需要刪除則刪除,節省很多時間.......


#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <climits>//形如INT_MAX一類的
#define MAX 111111
# define MAXM 51111
#define INF 0x7FFFFFFF
#define REP(i,s,t) for(int i=(s);i<=(t);++i)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#define L(x) x<<1
#define R(x) x<<1|1
# define eps 1e-5
//#pragma comment(linker, "/STACK:36777216") ///傳說中的外掛
using namespace std;

struct sbt {
    int l,r,s,key;
} tr[MAX];
int top , root;
void left_rot(int &x) {
    int y = tr[x].r;
    tr[x].r = tr[y].l;
    tr[y].l = x;
    tr[y].s = tr[x].s; //轉上去的節點數量爲先前此處節點的size
    tr[x].s = tr[tr[x].l].s + tr[tr[x].r].s + 1;
    x = y;
}

void right_rot(int &x) {
    int y = tr[x].l;
    tr[x].l = tr[y].r;
    tr[y].r = x;
    tr[y].s = tr[x].s;
    tr[x].s = tr[tr[x].l].s + tr[tr[x].r].s + 1;
    x = y;
}

void maintain(int &x,bool flag) {
    if(flag == 0) { //左邊
        if(tr[tr[tr[x].l].l].s > tr[tr[x].r].s) {//左孩子左子樹size大於右孩子size
            right_rot(x);
        } else if(tr[tr[tr[x].l].r].s > tr[tr[x].r].s) {//左孩子右子樹size大於右孩子size
            left_rot(tr[x].l);
            right_rot(x);
        } else return ;
    } else { //右邊
        if(tr[tr[tr[x].r].r].s > tr[tr[x].l].s) { //右孩子的右子樹大於左孩子
            left_rot(x);
        } else if(tr[tr[tr[x].r].l].s > tr[tr[x].l].s) { //右孩子的左子樹大於左孩子
            right_rot(tr[x].r);
            left_rot(x);
        } else return ;
    }
    maintain(tr[x].l,0);
    maintain(tr[x].r,1);
}

void insert(int &x,int key) {
    if(x == 0) { //空節點
        x = ++ top;
        tr[x].l = tr[x].r = 0;
        tr[x].s = 1;
        tr[x].key = key;
    } else {
        tr[x].s ++;
        if(key < tr[x].key) insert(tr[x].l,key);
        else insert(tr[x].r,key);
        maintain(x,key >= tr[x].key);
    }
}
int del(int &p,int w) {
    if (tr[p].key==w || (tr[p].l == 0 && w < tr[p].key) || (tr[p].r == 0 && w > tr[p].key)) {
        int delnum = tr[p].key;
        if (tr[p].l == 0 || tr[p].r == 0) p = tr[p].l + tr[p].r;
        else tr[p].key=del(tr[p].l,INF);
        return delnum;
    }
    if (w < tr[p].key) return del(tr[p].l,w);
    else return del(tr[p].r,w);
}

int remove(int &x,int key) {
    int k;
    tr[x].s --;
    if(key == tr[x].key || (key < tr[x].key && tr[x].l == 0) || (key > tr[x].key && tr[x].r == 0)) {
        k = tr[x].key;
        if(tr[x].l && tr[x].r) {
            tr[x].key = remove(tr[x].l,tr[x].key + 1);
        } else {
            x = tr[x].l + tr[x].r;
        }
    } else if(key > tr[x].key) {
        k = remove(tr[x].r,key);
    } else if(key < tr[x].key) {
        k = remove(tr[x].l,key);
    }
    return k;
}

int getmin() { //二叉搜索樹找最小值
    int x;
    for(x = root; tr[x].l; x = tr[x].l) ;
    return tr[x].key;
}
int getmax() {
    int x;
    for(x = root ; tr[x].r; x = tr[x].r) ;
    return tr[x].key;

}

int select(int &x,int k) { //求第k小數
    int r = tr[tr[x].l].s + 1;
    if(r == k) return tr[x].key;
    else if(r < k) return select(tr[x].r,k - r);
    else return select(tr[x].l,k);
}

struct node {
    int l,r,p,id,ans;
} qes[MAXM];

int a[MAX];
bool cmp(const node & a, const node & b) {
    if(a.l == b.l) return a.r < b.r;
    return a.l < b.l;
}

bool cmp2(const node &a, const node & b) {
    return a.id < b.id;
}
int main() {
    top = 0;
    root = 0;
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++) scanf("%d",&a[i]);
    for(int i=1; i<=m; i++) {
        scanf("%d%d%d",&qes[i].l,&qes[i].r,&qes[i].p);
        qes[i].id = i;
    }
    sort(qes+1,qes+m+1,cmp);
    for(int i=qes[1].l; i<=qes[1].r; i++) {
        insert(root,a[i]);
    }
    qes[1].ans = select(root,qes[1].p);
    for(int i=2; i<=m; i++) {
        if(qes[i].l <= qes[i-1].r) {
            if(qes[i].l > qes[i-1].l) {
                for(int j=qes[i-1].l; j<qes[i].l; j++) remove(root,a[j]);
            }
            if(qes[i].r < qes[i-1].r) {
                for(int j=qes[i].r+1; j<=qes[i-1].r; j++) remove(root,a[j]);
            }
            if(qes[i].r > qes[i-1].r) {
                for(int j=qes[i-1].r+1; j<=qes[i].r; j++) insert(root,a[j]);
            }
        } else {
            for(int j=qes[i-1].l; j<=qes[i-1].r; j++) {
                remove(root,a[j]);
            }
            for(int j=qes[i].l; j<=qes[i].r; j++) {
                insert(root,a[j]);
            }
        }
        qes[i].ans = select(root,qes[i].p);
    }
    sort(qes+1,qes+m+1,cmp2);
    for(int i=1; i<=m; i++) printf("%d\n",qes[i].ans);
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章