Peter's codebook A blog full of codes

CodeForces 610D -- Vika and Segments

解法

線段樹 + 掃描線

用線段樹維護每個 y 方向的線段,取得 y 方向的線段和, 一邊掃過 x 方向,算出每個 y 方向線段間圍起來的面積和。

這題比 POJ1151 更困難一些。

差別在於這題輸入是閉區間,還有測資範圍比較大。

傳送門

CF610D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <functional>
#include <vector>
#include <set>
#include <assert.h>

using std::vector;
vector<long long int> y_search;
struct SegmentTree {
    enum{ MAXN=400010, TREEND=4, TREENN=MAXN*TREEND};
    long long int  seg[TREENN]; // neg, pos
    long long int  range[TREENN]; // neg, pos

#define HALF_OPEN_INTERVAL
    inline int LEFT(const int &i) { return i<<1; }
    inline int RIGHT(const int &i) { return i<<1|1; }
    inline void init(int n) {
        n*=TREEND;
        std::fill(this->seg, this->seg+n+1, 0);
        std::fill(this->range, this->range+n+1, 0);
    }

#ifndef HALF_OPEN_INTERVAL
    // 節點紀錄閉區間   [, ]
#define IN_RANGE (qL<=L && qR>=R)
#define OO_RANGE (L>qR || R<qL)
#else
    // 節點紀錄半開區間 [, )
#define IN_RANGE (qL<=L && qR>=R)
#define OO_RANGE (L>=qR || R<=qL)
#endif
    inline void _pull(int lev, int L, int R) {
        range[lev] = seg[lev]>0?(y_search[R]-y_search[L]):(range[LEFT(lev)]+range[RIGHT(lev)]);
    }
    void update(int L, int R, int qL, int qR, int lev, int op) {
        assert(lev<TREENN);
        if (OO_RANGE) return;
        int M = (L+R)>>1;
        if (IN_RANGE) {
            seg[lev] += (op?1:-1);
            range[lev] = seg[lev]>0?(y_search[R]-y_search[L]):(range[LEFT(lev)]+range[RIGHT(lev)]);
            return;
        }
        update(L, M, qL, qR, LEFT(lev), op);
#ifndef HALF_OPEN_INTERVAL
        update(M+1, R, qL,qR, RIGHT(lev),op);
#else
        update(M, R, qL,qR, RIGHT(lev),op);
#endif
        _pull(lev, L, R);
    }

    inline long long int query(int R) {
        return range[1];
    }
#undef IN_RANGE
#undef OO_RANGE
#undef LEFT
#undef RIGHT
#undef HALF_OPEN_INTERVAL
};

struct NODE {
    NODE(long long int x, long long int y1, long long int y2, bool state): x(x), y1(y1), y2(y2), state(state) {}
    long long int x, y1, y2;
    bool state; // 1, enter; 0, exit
};
const bool operator<(const NODE &left, const NODE &right) {
    if (left.x!=right.x) return left.x<right.x;
    return left.state > right.state; // reverse order
}

using namespace std;
SegmentTree *tree;
vector<NODE> data;
set<long long int> yseg;

int main(void) {
    int N;
    tree = new SegmentTree;
    scanf("%d",&N);
    for (int i=0; i<N; ++i) {
        long long int x1, y1, x2, y2;
        scanf("%lld %lld %lld %lld",&x1,&y1,&x2,&y2);
        if (x1==x2) { //verticle
            ++x2;
            if (y1>y2) swap(y1,y2);
            ++y2;
        } else { // horizonal
            ++y2;
            if (x1>x2) swap(x1,x2);
            ++x2;
        }
        data.push_back(NODE(x1,y1,y2,true));
        data.push_back(NODE(x2,y1,y2,false));
        yseg.insert(y1); yseg.insert(y2);
    }
    sort(data.begin(),data.end());
    y_search.reserve(yseg.size()+1);
    y_search.push_back(-214740000000LL); // not used
    for (set<long long int>::iterator v=yseg.begin(); v!=yseg.end(); ++v)
        y_search.push_back(*v);
    int segN = yseg.size();
    yseg.clear();
    tree->init(segN);
#define FIND_IDX(_X) (lower_bound(y_search.begin(), y_search.end(), ( _X) )-y_search.begin())
    tree->update(1, segN, FIND_IDX(data[0].y1), FIND_IDX(data[0].y2), 1, 1);
    NODE left = data[0];
    long long int sum=0;
    for (vector<NODE>::iterator v=data.begin()+1; v!=data.end(); ++v) {
        NODE &inst = *v;
        int idxy1 = FIND_IDX(inst.y1);
        int idxy2 = FIND_IDX(inst.y2);
        sum += tree->query(segN) * (inst.x-left.x);
        tree->update(1, segN, idxy1, idxy2, 1, inst.state);
        left = inst;
    }
    printf("%lld\n", sum);
    delete tree;
    return 0;
}
comments powered by Disqus