2016年3月3日 星期四

(Ioicamp Judge) 26. 區間MEX

區間MEX

Time Limit: 5s


Description

定義一個非負整數形成集合的 mex(minimum excludant)為最小不在該集合的非負整數,例如:
  • mex({1,2,3})=0
  • mex({0,1,2,3,5,8})=4
現在給你一個長度 N 的序列 A,你要支援以下詢問:
  • 求一個區間內所有數形成的集合的 mex 值。

Input Format

第一行有一個正整數 T,代表總共有幾筆測試資料。
每筆測試資料第一行包含兩個正整數 N,M,代表序列的長度以及詢問數。
接下來包含 N 個由空白隔開的非負整數 Ai,代表序列的元素。
接下來包含 M 行,每行包含兩個正整數 l,r
代表一個詢問,請輸出區間 {Al,,Ar} 的 mex 值。
  • 1T20
  • 1N,M105
  • 0Ai109
  • 詢問: 1lrN

Output Format

對於每個詢問,請輸出一行包含一個非負整數,代表該詢問區間的 mex

Sample Input

1
10 7
1 0 2 3 1 5 4 6 3 7
1 1
1 3
6 10
3 5
4 9
2 3
1 10

Sample Output

0
3
0
0
0
1
8

這題有兩種解法:

一種是我的隊友(很電的國手:余柏序)在賽中寫的:http://codingsimplifylife.blogspot.tw/2016/02/ioi-camp-judge-26mex.html

另外的解法是說:

因為數值>10^5就沒有用了(因為mex的定義是最小的非負整數,又最多只會出現10^5的數字,所以數值>10^5就可以不用考慮了)。

所以,我先把所有的詢問按照右界排序,數值線段樹裡面存的是 "這個數值最後出現在哪裡(沒有的話就-INF)" !之後開始慢慢的push值(因問詢問按照右界排序)。

然後再查詢線段樹的時候,盡量往左走

這樣就OK了



#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;

const int MAX_N = 100010;
const int MAX_M = 100010;

struct QUERY {
    int l;
    int r;
    int id;
} Query[MAX_M];

int ans[MAX_N];
int v[MAX_N];

bool operator<(const QUERY& q1,const QUERY& q2) {
    return q1.r<q2.r || q1.r==q2.r&&q1.l<q2.l;
}

struct Node {
    int val;
    Node* lc;
    Node* rc;
    Node () {
        val=-1;
        lc=rc=NULL;
    }
    void pull() {
        val = min(lc->val,rc->val);
    }
};

Node* Build(int L,int R) {
    Node* node = new Node();
    if (L==R) return node;
    int mid=(L+R)>>1;
    node->lc=Build(L,mid);
    node->rc=Build(mid+1,R);
    node->pull();
    return node;
}

void modify(Node* node,int L,int R,int pos,int val) {
    if (L==R) {
        node->val = val;
        return;
    }
    int mid=(L+R)>>1;
    if (pos<=mid) modify(node->lc,L,mid,pos,val);
    else modify(node->rc,mid+1,R,pos,val);
    node->pull();
    return; 
}

int query(Node* node,int L,int R,int val) { //val equals to query.l
    if (L==R) return L;
    int mid=(L+R)>>1;
    if (node->lc->val < val) return query(node->lc,L,mid,val);
    else return query(node->rc,mid+1,R,val);
}

int main () {
    int T;
    scanf("%d",&T);
    while (T--) {
        int n,m;
        scanf("%d %d",&n,&m);
        for (int x=1;n>=x;x++) {
            scanf("%d",&v[x]);
            if (v[x]>100002) v[x]=100003;
        }
        Node* root = Build(0,MAX_N);
        for (int x=0;m>x;x++) {
            scanf("%d %d",&Query[x].l,&Query[x].r);
            Query[x].id=x;
        }
        sort(Query,Query+m);
        int nr;
        int id=1;
        for (int x=0;m>x;x++) {
            int L=Query[x].l;
            int R=Query[x].r;
            int t=Query[x].id;
            while (R>=id) {
                modify(root,0,MAX_N,v[id],id);
                id++;
            }
            ans[t]=query(root,0,MAX_N,L);
        }
        for (int x=0;m>x;x++) printf("%d\n",ans[x]);
    }
}

沒有留言:

張貼留言