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; }

时间: 2024-10-27 05:51:46

zstu4186——线段树——表白计划(未完成)的相关文章

【BZOJ3207】花神的嘲讽计划I 可持久化线段树/莫队

看到题目就可以想到hash 然后很自然的联想到可持久化权值线段树 WA:base取了偶数 这道题还可以用莫队做,比线段树快一些 可持久化线段树: 1 #include<bits/stdc++.h> 2 #define ll long long 3 #define uint unsigned int 4 #define ull unsigned long long 5 #define inf 4294967295 6 #define N 100005 7 #define M 100005 8 #

BZOJ 3207: 花神的嘲讽计划Ⅰ( hash + 可持久化线段树 )

O(NK)暴力搞出所有子串的哈希值, 然后就对哈希值离散化建权值线段树, 就是主席树的经典做法了.总时间复杂度O(NK+(N+Q)logN) -------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cctype> using namespa

[kuangbin]带你飞之&#39;线段树&#39;专题(未完成)

// 带飞网址 https://vjudge.net/article/187 专题七 线段树 HDU 1166 敌兵布阵HDU 1754 I Hate It√ POJ 3468 A Simple Problem with IntegersPOJ 2528 Mayor's postersHDU 1698 Just a HookZOJ 1610 Count the ColorsPOJ 3264 Balanced LineupHDU 4027 Can you answer these queries?

【洛谷】P2073 送花 [2017年6月计划 线段树01]

P2073 送花 题目背景 小明准备给小红送一束花,以表达他对小红的爱意.他在花店看中了一些花,准备用它们包成花束. 题目描述 这些花都很漂亮,每朵花有一个美丽值W,价格为C. 小明一开始有一个空的花束,他不断地向里面添加花.他有以下几种操作: 操作 含义 1 W C 添加一朵美丽值为W,价格为C的花. 3 小明觉得当前花束中最便宜的一朵花太廉价,不适合送给小红,所以删除最便宜的一朵花. 2 小明觉得当前花束中最贵的一朵花太贵,他心疼自己的钱,所以删除最贵的一朵花. -1 完成添加与删除,开始包

洛谷P1774 最接近神的人_NOI导刊2010提高(02) [2017年6月计划 线段树03]

P1774 最接近神的人_NOI导刊2010提高(02) 题目描述 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案.而石门上方用古代文写着“神的殿堂”.小FF猜想里面应该就有王室的遗产了.但现在的问题是如何打开这扇门…… 仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的.而最聪明的人往往通过一种仪式选拔出来.仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种操作,即

洛谷P2826 [USACO08NOV]光开关Light Switching [2017年6月计划 线段树02]

P2826 [USACO08NOV]光开关Light Switching 题目描述 Farmer John tries to keep the cows sharp by letting them play with intellectual toys. One of the larger toys is the lights in the barn. Each of the N (2 <= N <= 100,000) cow stalls conveniently numbered 1..N

【模板】 递归线段树 [2017年五月计划 清北学堂51精英班Day4]

P3372 [模板]线段树 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的

[bzoj3207]花神的嘲讽计划Ⅰ[可持久化线段树,hash]

将每k个数字求一个哈希值,存入可持久化线段树,直接查询即可 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cmath> 7 #include <ctime> 8 9 using namespace std; 10 11 #define

[补档计划] 树4 - 线段树

[CF787D] Legacy 题意 $N$ 个点, $M$ 条连边操作: $1~u~v~w~:~u\rightarrow v$ . $2~u~l~r~w~:~u\rightarrow [l, r]$ $3~u~l~r~w~:~[l, r]\rightarrow u$ . 给定点 $s$ , 求单源最短路. $N\le 10^5$ . 分析 考虑使用 线段树结构 优化 建图. 建立一棵线段树, 每个点表示一个区间. 拆点, 线段树的每个点拆成 入点 和 出点 . 出线段树 的儿子连父亲, 因为可