扫描线(线段树)+贪心 ZOJ 3953

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5572

Intervals

Time Limit: 1 Second      Memory Limit: 65536 KB      Special Judge

Chiaki has n intervals and the i-th of them is [liri]. She wants to delete some intervals so that there does not exist three intervals ab and c such that a intersects with bb intersects with c and c intersects with a.

Chiaki is interested in the minimum number of intervals which need to be deleted.

Note that interval a intersects with interval b if there exists a real number x such that la ≤ x ≤ ra and lb ≤ x ≤ rb.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains an integer n (1 ≤ n ≤ 50000) -- the number of intervals.

Each of the following n lines contains two integers li and ri (1 ≤ li < ri ≤ 109) denoting the i-th interval. Note that for every 1 ≤ i < j ≤ nli ≠ lj or ri ≠ rj.

It is guaranteed that the sum of all n does not exceed 500000.

Output

For each test case, output an integer m denoting the minimum number of deletions. Then in the next line, output m integers in increasing order denoting the index of the intervals to be deleted. If m equals to 0, you should output an empty line in the second line.

Sample Input

1
11
2 5
4 7
3 9
6 11
1 12
10 15
8 17
13 18
16 20
14 21
19 22

Sample Output

4
3 5 7 10

Author: LIN, Xi
Source: The 17th Zhejiang University Programming Contest Sponsored by TuSimple

 

题目大意:给你n个区间,这n个区间里面可能存在这样的区间,即a交b,b交c,c交a。问最少删除多少个,才能使得不存在这样的区间,并输出删除的是什么区间。

思路:扫面线一遍,从左往右扫(就是单点查询,md我今天才知道原来这是一维扫描线,打比赛的时候完全不知道)。然后每次都往priority_queue里面放入目前询问到节点的右端点,当cnt>=3的时候贪心的删除最右边的端点即可。

 

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = 100000 + 5;
int n;
vector<int> ve;
int l[maxn], r[maxn];
vector<pair<int, int> > qujian[maxn];
struct Point{
    int val, lazy;
}tree[maxn << 2];

void buildtree(int l, int r, int o){
    tree[o].val = tree[o].lazy = 0;
    if (l == r){
        return ;
    }
    int mid = (l + r) / 2;
    if (l <= mid) buildtree(l, mid, o << 1);
    if (r > mid) buildtree(mid + 1, r, o << 1 | 1);
}

void push_down(int o){
    int lb = o << 1, rb = o << 1 | 1;
    tree[lb].lazy += tree[o].lazy; tree[lb].val += tree[o].lazy;
    tree[rb].lazy += tree[o].lazy; tree[rb].val += tree[o].lazy;
    tree[o].lazy = 0;
}

void update(int ql, int qr, int l, int r, int o, int add){
    //printf("ql = %d qr = %d l = %d r = %d\n", ql, qr, l, r);
    if (ql <= l && qr >= r){
        tree[o].lazy += add;
        tree[o].val += add;
        return ;
    }
    if (tree[o].lazy != 0) push_down(o);
    int mid = (l + r) / 2;
    if (ql <= mid) update(ql, qr, l, mid, o << 1, add);
    if (qr > mid) update(ql, qr, mid + 1, r, o << 1 | 1, add);
    tree[o].val = max(tree[o << 1].val, tree[o << 1 | 1].val);
}

int query(int ql, int qr, int l, int r, int o){
    if (ql <= l && qr >= r){
        return tree[o].val;
    }
    if (tree[o].lazy != 0) push_down(o);
    int mid = (l + r) / 2;
    int maxval = 0;
    if (ql <= mid) maxval = max(maxval, query(ql, qr, l, mid, o <<1));
    if (qr > mid) maxval = max(maxval, query(ql, qr, mid + 1, r, o << 1| 1));
    tree[o].val = max(tree[o << 1].val, tree[o << 1 | 1].val);
    return maxval;
}

void solve(){
    int ans = 0;
    vector<int> tmp;
    buildtree(1, 2 * n, 1);
    for (int i = 1; i <= n; i++){
        update(l[i], r[i], 1, 2 * n, 1, 1);
    }
    priority_queue<pair<int, int> > que;
    for (int i = 1; i <= 2 * n; i++){
        if (qujian[i].size()){
            for (int j = 0; j < qujian[i].size(); j++){
                que.push(qujian[i][j]);
            }
            int cnt = query(i, i, 1, 2 * n, 1);
            while (cnt >= 3){
                cnt--;
                pair<int, int> pa = que.top(); que.pop();
                update(i, pa.fi, 1, 2*n, 1, -1);
                ans++;
                tmp.push_back(pa.se);
            }
            /*for (int j = qujian[i].size() - 1; j >= 0; j--){
                int L = i, R = qujian[i][j].fi;

                int cnt = query(L, R, 1, 2 * n, 1);
                 cout<<L << ' ' << R<< ' ' <<cnt<<endl;
                if (cnt >= 3){
                    ans++;
                    update(L, R, 1, 2 * n, 1, -1);
                    tmp.push_back(qujian[i][j].se);
                }
                else break;
            }*/
        }
    }
    sort(ALL(tmp));
    printf("%d\n", ans);
    for (int i = 0; i < tmp.size(); i++){
        printf("%d%c", tmp[i], i == tmp.size()-1 ? '\n' : ' ');
    }
}

int main(){
    int t; cin >> t;
    while (t--){
        ve.clear();
        scanf("%d", &n);
        for (int i = 0; i <= 2 * n; i++) qujian[i].clear();
        for (int i = 1; i <= n; i++){
            scanf("%d%d", l + i, r + i);
            ve.push_back(l[i]);
            ve.push_back(r[i]);
        }
        sort(ALL(ve));
        ve.erase(unique(ALL(ve)), ve.end());
        for (int i = 1; i <= n; i++){
            l[i] = lower_bound(ALL(ve), l[i]) - ve.begin() + 1;
            r[i] = lower_bound(ALL(ve), r[i]) - ve.begin() + 1;
            qujian[l[i]].push_back(mk(r[i], i));
        }
        for (int i = 1; i <= 2 * n; i++){
            if (qujian[i].size()){
                sort(ALL(qujian[i]));
            }
        }
        solve();
    }
    return 0;
}
View Code

 

posted @ 2017-04-10 19:22  知る奇迹に  阅读(332)  评论(0编辑  收藏  举报