zstu4186——线段树——表白计划(未完成)

Description

众所周知,程序员是种神奇的没有妹子的生物。

有一个很厉害的程序员Doge,他没有妹子。于是他将自己心仪的n个妹子编号为1到n,然后制定了m个表白计划在接下来的t天内向妹子表白,对于某一个计划,他会在计划的第L天到第R天向编号为x的妹子每天表白一次。由于计划很多,有些表白区间可能有重复,所以他有可能在某一天跟同一个妹子表白很多次。他每一次表白被拒绝后都会收到被表白的妹子亲手写的好人卡,毫无悬念,他每一次都能收到好人卡。

现在Doge想知道在某些时间段他收到了多少张好人卡,还有这个时间段哪个妹子没有给过他好人卡,如果有多个妹子没有给过,他想知道编号最小的是哪个妹子。然而他正忙于制定下一个表白计划,所以请你这个程序员来帮下解决下吧!(PS:不要在意各种奇怪的事情,程序员本来就是个神奇的生物。)

Input

 题目有多组测试数据。

对于每一组测试数据,第一行有三个数n, m, t(1 <= n, m, t <= 80000),在接下来的m行里,每一行有三个数L, R, x (1 <= L <= R <= t, 1 <= x <= n)表示Doge将在第L天到第R天每天向第x个妹子表白一次。接下来一行有一个数Q(1 <= Q <= 80000),接下来有Q行询问。对于询问,我们规定一个特殊的数z,z初始为0。每次询问给你两个数L, R (1 <= L<=R<=t),表示询问的区间为第L+z天到第R+z天,如果R+z超过t的话,就把区间变为第t-(R-L)天到第t天。对于每次询问,需要求出这段区间内Doge收到的好人卡个数和没有给过Doge好人卡的最小的妹子编号,如果所有妹子都给了好人卡,那么编号为0,然后把编号赋值给z。

Output

 对于每次询问,输出为一行以一个空格间隔的两个数,第一个数为好人卡个数,第二个数为妹子编号。

Sample Input

5 5 10

1 3 1

3 5 2

7 9 3

2 4 4

8 10 5

4

1 6

6 8

1 9

4 6

Sample Output

9 3

5 1

14 0

3 1

HINT

 大意:拉来了题解,以后看专题的时候补上

询问包含两个部分,第一部分是求区间和,那么这个可以简单的通过两次前缀和搞定。  然后处理第二部分。  数据给出的是每个妹子发好人卡的时间段,借此可以得到每个妹子不发好人卡的时间段,容 易知道不发好人卡的时间段的总数也是O(m)的。  考虑对妹子们的下标[1,n]建一棵线段树。  设线段树上节点i对应的妹子区间为[li,ri],在节点i上保存妹子[li,ri]们不发好人卡的时间段。在 线段树上,包含妹子x的节点只有logn个,因此整棵线段树里最多包含mlogn个时间段。  接下来讲如何用这棵线段树处理询问(l,r):标号最小的不发好人卡的时间段完全包含[l,r]的妹 子是哪一个。  当走到线段树的节点i的时候,如果节点i的左儿子中存在完全包含[l,r]的时间段,那么往左儿 子走肯定是比右儿子要优的,因为左儿子包含的妹子们标号永远比右儿子小。否则就往右儿 子走。  接着处理子问题:怎样快速的判断线段树的一个节点中存的时间段们是否包含[l,r]。  我们来考虑对这个节点上的时间段们进行一些处理。设这些时间段们分别为[L1,R1],[L2,R2] ….[Lk,Rk],容易知道如果存在两个时间段a和b满足:La <= Lb 并且 Rb <= Ra,那么时间段 b就不需要存在了。那么对于这些只有相交/相离关系的线段,把他们按照Li从小到大排序 后,他们的Ri也会是升序的。那么接下来只要在这些线段间二分,就可以logn时间判断它们 是否包含[l,r]。

#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <vector> using namespace std; typedef long long ll; const int N = 100000+5; vector<pair<int,int> >  a[N], tmp, b[N]; ll sum[N];

struct Segtree { #define lson rt<<1, l, mid #define rson rt<<1|1, mid+1, r    vector<pair<int,int> > node[N<<2];

    void build(int rt, int l, int r) {        node[rt].clear();        for(int i = l;i <= r; i++) {            for(int j = 0;j < a[i].size(); j++) {                node[rt].push_back(make_pair(a[i][j].first, a[i] [j].second));            }        }        sort(node[rt].begin(), node[rt].end());        int top = 1;        for(int i = 1;i < node[rt].size(); i++) if(node[rt] [i].second > node[rt][top-1].second){            if(node[rt][i].first == node[rt][top-1].first)                node[rt][top-1].second = node[rt][i].second;            else                node[rt][top++] = node[rt][i];        }        node[rt].resize(top);        if(l == r)  return ;        int mid = l+r>>1;        build(lson); build(rson);    }

    int query(int rt, int l, int r, int x, int y) {        if(l == r)  return l;        int mid = l+r>>1;        if(check(rt<<1, x, y))  return query(lson, x, y);          return query(rson, x, y);    }

    inline bool check(int rt, int x, int y) {        int pos = lower_bound(node[rt].begin(), node[rt].end(), make_pair(x+1, 0))-node[rt].begin();        if(pos == 0 || node[rt][pos-1].second < y)   return false;        return true;    } }tree;

int n, m, t;

int main() {    //freopen("data.in", "r", stdin);    //freopen("data.out", "w", stdout);    while(scanf("%d%d%d", &n, &m, &t) != -1) {        for(int i = 1;i <= t; i++) sum[i] = 0;        for(int i = 1;i <= n; i++)  b[i].clear();        int l, r, x;        for(int i = 0;i < m; i++) {            scanf("%d%d%d", &l, &r, &x);            sum[l]++; sum[r+1]--;            b[x].push_back(make_pair(l, r));        }        for(int i = 1;i <= t; i++)  sum[i] += sum[i-1];        for(int i = 1;i <= t; i++)  sum[i] += sum[i-1];

        for(int i = 1;i <= n; i++) {            sort(b[i].begin(), b[i].end());            a[i].clear();            int cur = 1;            for(int j = 0;j < b[i].size(); j++) {                if(cur < b[i][j].first) a[i].push_back(make_pair(cur, b[i][j].first-1));                cur = max(cur, b[i][j].second+1);            }            if(cur <= t) {                a[i].push_back(make_pair(cur, t));            }        }        tree.build(1, 1, n);        int q, z = 0;        scanf("%d", &q);        while(q--) {            scanf("%d%d", &l, &r);            if(r+z <= t)    l += z, r += z;            else    l = t-(r-l), r = t;            if(tree.check(1, l, r)) z = tree.query(1, 1, n, l, r);            else    z = 0;            printf("%lld %d\n", sum[r]-sum[l-1], z);        }    }    return 0; }
View Code

 

你可能感兴趣的:(线段树)