zstuoj 4186 表白計劃(區間操作x線段樹)

題意:
。。
這道是zstu2015校賽題。。
傳送
思路:
對於第一個詢問,先維護差分序列,然後求對差分序列求兩次前綴和得到前綴和。
對第二個詢問。
假設用pair<int, int>來表示區間。
先把表白計劃按girl分開存,對每個girl處理出她不發好人卡的區間。
這一步是 O(mlogm),m 爲區間數
建一個線段樹,節點 v(l,r)包含girl_l到girl_r的不發好人卡的區間,注意要去掉那些被其他區間完全包含的區間。
處理出來的區間全部都從小到大排序。
每一層所有節點包含的區間數 O(m)
所以這一步時間複雜度 O(mlogmlogn),空間 O(mlogn)
最後處理查詢,可以用二分地在一個有序的區間序列裏查找是否包含某個區間。而找id最小的就很容易了。。
不錯的一道數據結構題,考察了基本的對區間的模擬操作,合併,查找,去重等。也對線段樹有很好的利用。

const int N = 80005;

typedef pair<int, int> pii;
typedef long long LL;

LL prf[N];
vector<pii> gl[N];
int n, m, t;

void range_inv(vector<pii>& v, int t) {
    vector<pii> tmp;
    int cur = 1;
    for(int i = 0; i < v.size(); ++ i) {
        if ( cur < v[i].first ) {
            tmp.push_back( make_pair(cur, v[i].first - 1) );
        }
        cur = max ( cur, v[i].second + 1 );
    }
    if ( cur <= t ) tmp.push_back( make_pair(cur, t) );
    tmp.swap(v);
}

bool contain(const vector<pii>& v, int l, int r) {
    int pos = upper_bound( v.begin(), v.end(), make_pair(l, INT_MAX) ) - v.begin();
    if ( !pos || v[pos - 1].second < r ) return 0;
    return 1;
}

vector<pii> tr[N<<2];
int qL, qR;
#define lc o<<1
#define rc o<<1|1
void build(int o, int l, int r) {
    vector<pii>& v = tr[o];
    if ( l == r ) {
        v = gl[l];
    } else {
        int m = (l + r) >> 1;
        build(lc, l, m);
        build(rc, m + 1, r);
        vector<pii>().swap(v);
        rep(i, l, r) v.insert(v.end(), gl[i].begin(), gl[i].end());
        sort(v.begin(), v.end());
        int top = 1;
        for (int i = 1; i < v.size(); ++ i)
            if ( v[i].second > v[top - 1].second ) {
                if ( v[i].first == v[top - 1].first ) {
                    v[top - 1].second = v[i].second;
                } else {
                    v[top ++] = v[i];
                }
            }
        v.resize(top);
    }
}

int query(int o, int l, int r) {
    if ( l == r ) return l;
    int m = (l + r) >> 1;
    if ( contain(tr[lc], qL, qR) )
        return query(lc, l, m);
    return query(rc, m + 1, r);
}

int main() {
#ifdef _LOCA_ENV_
    freopen("input.in", "r", stdin);
#endif // _LOCA_ENV
    while ( scanf("%d%d%d", &n, &m, &t) != EOF ) {
        memset(prf, 0, sizeof(prf));
        rep(i, 1, n) vector<pii>().swap(gl[i]);
        rep(i, 1, m) {
            int l, r, x;
            scanf("%d%d%d", &l, &r, &x);
            prf[l] += 1;
            prf[r+1] -= 1;
            gl[x].push_back( make_pair(l, r) );
        }
        rep(i, 1, t) prf[i] += prf[i-1];
        rep(i, 1, t) prf[i] += prf[i-1];
        rep(i, 1, n) {
            sort(gl[i].begin(), gl[i].end());
            range_inv(gl[i], t);
        }

        build(1, 1, n);

        int z = 0, q;
        scanf("%d", &q);
        rep(o, 1, q) {
            int l, r;
            scanf("%d%d", &l, &r);
            l += z, r += z;
            if ( r > t ) {
                l = t - ( r - l );
                r = t;
            }
            qL = l, qR = r;
            if ( !contain(tr[1], l, r) )
                z = 0;
            else
                z = query(1, 1, n);
            printf("%lld %d\n", prf[r] - prf[l-1], z);
        }
    }
    return 0;
}
發佈了278 篇原創文章 · 獲贊 10 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章