[luoguP3606] [USACO17JAN]Building a Tall Barn建谷仓(贪心 + 线段树)

传送门

把线段都读进来然后排序,先按右端点为第一关键字从小到大排序,后按左端点为第二关键字从小到大排序。

注意不能先按左端点后按右端点排序,否则会出现大包小的情况,如下:

——————

  ———

    —

然后直接线段树搞就行,先求区间最小值,如果大于零就更新统一减1。

——代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #define root 1, 1, n
 5 #define ls now << 1, l, mid
 6 #define rs now << 1 | 1, mid + 1, r
 7
 8 const int INF = ~(1 << 31), MAXN = 100001;
 9 int n, m, ans;
10 int minn[MAXN << 2], add[MAXN << 2];
11
12 struct node
13 {
14     int a, b;
15 }p[MAXN];
16
17 inline void swap(int &x, int &y)
18 {
19     x ^= y ^= x ^= y;
20 }
21
22 inline void push_up(int now)
23 {
24     minn[now] = std::min(minn[now << 1], minn[now << 1 | 1]);
25 }
26
27 inline void push_down(int now, int len)
28 {
29     if(!add[now]) return;
30     add[now << 1] += add[now];
31     add[now << 1 | 1] += add[now];
32     minn[now << 1] += add[now];
33     minn[now << 1 | 1] += add[now];
34     add[now] = 0;
35 }
36
37 inline void build(int now, int l, int r)
38 {
39     if(l == r)
40     {
41         scanf("%d", &minn[now]);
42         return;
43     }
44     int mid = (l + r) >> 1;
45     build(ls);
46     build(rs);
47     push_up(now);
48 }
49
50 inline bool cmp(node x, node y)
51 {
52     return x.b == y.b ? x.a < y.a : x.b < y.b;
53 }
54
55 inline int query(int x, int y, int now, int l, int r)
56 {
57     if(x <= l && r <= y) return minn[now];
58     if(l > y || r < x) return INF;
59     push_down(now, r - l + 1);
60     int mid = (l + r) >> 1;
61     return std::min(query(x, y, ls), query(x, y, rs));
62 }
63
64 inline void update(int x, int y, int now, int l, int r)
65 {
66     if(x <= l && r <= y)
67     {
68         minn[now]--;
69         add[now]--;
70         return;
71     }
72     if(l > y || r < x) return;
73     push_down(now, r - l + 1);
74     int mid = (l + r) >> 1;
75     update(x, y, ls);
76     update(x, y, rs);
77     push_up(now);
78 }
79
80 int main()
81 {
82     int i, j;
83     scanf("%d %d", &n, &m);
84     build(root);
85     for(i = 1; i <= m; i++)
86     {
87         scanf("%d %d", &p[i].a, &p[i].b);
88         if(p[i].a > p[i].b) swap(p[i].a, p[i].b);
89     }
90     std::sort(p + 1, p + m + 1, cmp);
91     for(i = 1; i <= m; i++)
92         if(query(p[i].a, p[i].b, root) > 0)
93             ans++, update(p[i].a, p[i].b, root);
94     printf("%d", ans);
95     return 0;
96 }

时间: 2024-10-11 16:07:42

[luoguP3606] [USACO17JAN]Building a Tall Barn建谷仓(贪心 + 线段树)的相关文章

Bzoj 1696: [Usaco2007 Feb]Building A New Barn新牛舍 中位数,数学

1696: [Usaco2007 Feb]Building A New Barn新牛舍 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 394  Solved: 181[Submit][Status][Discuss] Description 经过多年的积蓄,农夫JOHN决定造一个新的牛舍.他知道所有N(2 <= N <= 10,000)头牛的吃草位置,所以他想把牛舍造在最方便的地方. 每一头牛吃草的位置是一个整数点(X_i, Y_i) (-10,0

HDU5669 Road 分层最短路+线段树建图

分析:(官方题解) 首先考虑暴力,显然可以直接每次O(n^2) ?的连边,最后跑一次分层图最短路就行了. 然后我们考虑优化一下这个连边的过程 ,因为都是区间上的操作,所以能够很明显的想到利用线段树来维护整个图, 连边时候找到对应区间,把线段树的节点之间连边.这样可以大大缩减边的规模,然后再跑分层图最短路就可以了. 但是这样建图,每一次加边都要在O(logn)个线段树节点上加边,虽然跑的非常快,但是复杂度仍然是不科学的. 为了解决边的规模的问题,开两棵线段树,连边时候可以新建一个中间节点,在对应区

线段树建图

对于一个图,n个节点,有向边,求点s到其他所有点的最短路. 题目给的边的方式: u -> v [l,r] -> v v -> [l,r] 这样的话边数是O(n^2)级别的,怎么做? 假设把[1,n]建成segment tree 后,有tot个节点. 则建一个新图,新图有2 * tot + n个节点 新图多了2 * tot个节点,表示2棵线段树A,B 点的编号分类: A - [1,tot] B - [tot + 1,2 * tot] C - [2 * tot + 1,2 * tot + n

洛谷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

洛谷P3372 【模板】线段树 1

P3372 [模板]线段树 1 153通过 525提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 [模板]线段树1(AAAAAAAAA- [模板]线段树1 洛谷评测机出问题了吗? 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接

【bzoj4276】[ONTAK2015]Bajtman i Okr?g?y Robin 线段树优化建图+费用流

题目描述 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢走c[i]元.作为保安,你在每一段长度为1的时间内最多只能制止一个强盗,那么你最多可以挽回多少损失呢? 输入 第一行包含一个正整数n(1<=n<=5000),表示强盗的个数. 接下来n行,每行包含三个正整数a[i],b[i],c[i](1<=a[i]<b[i]<=5000,1<=c[i]

二分查找or线段树(借教室洛谷1083vijos1782NOIP 2012 提高组 第二天 第二题)

在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借教室的信息,我们自然希望编程解决这个问题.我们需要处理接下来n天的借教室信息,其中第i天学校有ri个教室可供租借.共有m份订单,每份订单用三个正整数描述,分别为dj,sj,tj,表示某租借者需要从第sj天到第tj天租借教室(包括第sj天和第tj天),每天需要租借dj个教室. 我们假定,租借者对教室的大小.地点没有要求.即对于每份

【vijos】1750 建房子(线段树套线段树+前缀和)

https://vijos.org/p/1750 是不是我想复杂了.... 自己yy了个二维线段树,然后愉快的敲打. 但是wa了两法.......sad 原因是在处理第二维的更新出现了个小问题,sad. void pushup1(int x) { for1(i, 1, mm<<2) mn[x][i]=min(mn[lc][i], mn[rc][i]); } 这里注意是mm*4...我该好好想想了..这是在dbg的时候找出来的问题.sad. 我觉得很奇怪,线段树的底层节点一共就mm个,那么整棵树

POJ 1436 Horizontally Visible Segments(线段树建图+枚举)

题目连接:http://poj.org/problem?id=1436 题意:给一些线段,每个线段有三个值y1, y2, x代表起点为(x, y1),终点为(x, y2)的线段.当从一个线段可以作水平线到另一个线段并且不穿过其他线段时,就称这两个线段时水平可见的.当三个线段可以两两水平可见,就称为形成一个线段三角.问:在这些线段中有多少个这样的线段三角? 分析:可以把每条线段看做是一个点,如果它和其他线段是水平可见的,就将这两个点相连,由于是无向图,就是你能看到我,我也能看到你,所以需要连接两次