Hacker Cups and Balls Gym - 101234A 二分+线段树

题目:题目链接

题意:有编号从1到n的n个球和n个杯子. 每一个杯子里有一个球, 进行m次排序操作,每次操作给出l,r. 如果l<r,将[l,r]范围内的球按升序排序, 否则降序排, 问中间位置的数是多少.

思路:

  暴力复杂度为m*nlog(n), 不能暴力排序

  二分答案, 对于当前mid, 我们将大于等于mid的数记为1, 否则记0, 则排序就是将某个区间的数改为1或0, 通过线段树区间更新可以方便的做到, 对排序后的结果查询判断二分区间应该取左还是取右, 若中间的数是1, 则说明答案大于等于当前的数, l右移, 否则左移

AC代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <cmath>
  6 #include <algorithm>
  7 #include <vector>
  8 #include <string>
  9 #include <map>
 10 #include <set>
 11 #include <unordered_map>
 12 #include <unordered_set>
 13 #include <queue>
 14 #include <stack>
 15 #include <list>
 16
 17 #define FRER() freopen("in.txt", "r", stdin)
 18 #define FREW() freopen("out.txt", "w", stdout)
 19
 20 #define INF 0x3f3f3f3f
 21 #define eps 1e-8
 22
 23 using namespace std;
 24
 25 const int maxn = 1e5 + 5;
 26
 27 int a[maxn], ql[maxn], qr[maxn], tree[maxn << 2], lazy[maxn << 2];
 28
 29 void build(int l, int r, int rt, int num) {
 30     lazy[rt] = 0;
 31     if(l == r) {
 32         tree[rt] = (a[l] >= num);
 33         return ;
 34     }
 35     int m = (l + r) >> 1;
 36     build(l, m, rt << 1, num);
 37     build(m + 1, r, rt << 1|1, num);
 38     tree[rt] = tree[rt << 1] + tree[rt << 1|1];
 39 }
 40
 41 void pushdown(int l, int r, int rt) {
 42     int m = (l + r) >> 1;
 43     lazy[rt << 1] = lazy[rt << 1|1] = lazy[rt];
 44     if(lazy[rt] == 1) {
 45         tree[rt << 1|1] = min(tree[rt], r - m);
 46         tree[rt << 1] = tree[rt] - tree[rt << 1|1];
 47     }
 48     else if(lazy[rt] == 2){
 49         tree[rt << 1] = min(tree[rt], m - l + 1);
 50         tree[rt << 1|1] = tree[rt] - tree[rt << 1];
 51     }
 52     lazy[rt] = 0;
 53 }
 54
 55 int querySum(int x, int y, int l, int r, int rt) {
 56     if(x <= l && y >= r) return tree[rt];
 57     if(lazy[rt]) pushdown(l, r, rt);
 58     int m = (l + r) >> 1, sum = 0;
 59     if(x <= m) sum += querySum(x, y, l, m, rt << 1);
 60     if(y > m) sum += querySum(x, y, m + 1, r, rt << 1|1);
 61     return sum;
 62 }
 63
 64 int query(int pos, int l, int r, int rt) {
 65     if(l == r) return tree[rt];
 66     if(lazy[rt]) pushdown(l, r, rt);
 67     int m = (l + r) >> 1;
 68     if(pos <= m) return query(pos, l, m, rt << 1);
 69     else return query(pos, m + 1, r, rt << 1|1);
 70 }
 71
 72 void update(int x, int y, int l, int r, int rt, int flag, int sum) {
 73     if(x <= l && y >= r) {
 74         tree[rt] = sum;
 75         lazy[rt] = flag;
 76         return ;
 77     }
 78     if(lazy[rt]) pushdown(l, r, rt);
 79     int m = (l + r) >> 1;
 80     if(y <= m) update(x, y, l, m, rt << 1, flag, sum);
 81     else if(x > m) update(x, y, m + 1, r, rt << 1|1, flag, sum);
 82     else {
 83         int lsum, rsum;
 84         if(flag== 1) {
 85             rsum = min(sum, y - m);
 86             lsum = sum - rsum;
 87         }
 88         else if(flag == 2){
 89             lsum = min(sum, m - x + 1);
 90             rsum = sum - lsum;
 91         }
 92         update(x, m, l, m, rt << 1, flag, lsum);
 93         update(m + 1, y, m + 1, r, rt << 1|1, flag, rsum);
 94     }
 95     tree[rt] = tree[rt << 1] + tree[rt << 1|1];
 96 }
 97
 98 bool judge(int n, int m, int mid) {
 99     build(1, n, 1, mid);
100     for(int i = 0; i < m; ++i) {
101         int sum = querySum(min(ql[i], qr[i]), max(ql[i], qr[i]), 1, n, 1);
102         if(ql[i] <= qr[i]) update(ql[i], qr[i], 1, n, 1, 1, sum);
103         else update(qr[i], ql[i], 1, n, 1, 2, sum);
104     }
105     return query((1 + n) >> 1, 1, n, 1);
106 }
107
108 int main()
109 {
110     //FRER();
111     ios::sync_with_stdio(0);
112     cin.tie(0);
113
114     int n, m;
115     cin >> n >> m;
116     for(int i = 1; i <= n; ++i) cin >> a[i];
117     for(int i = 0; i < m; ++i) cin >> ql[i] >> qr[i];
118     int l = 1, r = n, ans;
119     while(l <= r) {
120         int mid = (l + r) >> 1;
121         if(judge(n, m, mid))
122             ans = mid, l = mid + 1;
123         else r = mid - 1;
124     }
125     cout << ans << endl;
126     return 0;
127 }

原文地址:https://www.cnblogs.com/fan-jiaming/p/10328127.html

时间: 2024-11-10 03:00:04

Hacker Cups and Balls Gym - 101234A 二分+线段树的相关文章

【BZOJ-3110】K大数查询 整体二分 + 线段树

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6265  Solved: 2060[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given a string s and q queries. For each query, you should answer that when all distinct substrings of string s were sorted lexicographically, which one is

(困难) CF 484E Sign on Fence,整体二分+线段树

Bizon the Champion has recently finished painting his wood fence. The fence consists of a sequence of n panels of 1 meter width and of arbitrary height. The i-th panel's height is hi meters. The adjacent planks follow without a gap between them. Afte

zoj 3888 Twelves Monkeys 二分+线段树维护次小值

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3888 Twelves Monkeys Time Limit: 5 Seconds      Memory Limit: 32768 KB James Cole is a convicted criminal living beneath a post-apocalyptic Philadelphia. Many years ago, the Earth's surf

bzoj1568: [JSOI2008]Blue Mary开公司 三分+二分+线段树

答案序列一定是个下凸壳,因此添加的等差数列与其之差是个单峰函数,可以先三分求出最值,再二分求出零点,然后用线段树,将得到的区间修改为一个等差数列. 这个做法应该比较好想吧,虽然比较慢…… #include<cstdio> #define Z int l=1,int r=N,int k=1 #define N 50000 #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define K l,r,k

计蒜客16492 building(二分线段树/分块)

题解: 考虑用线段树维护楼的最大值,然后这个问题就很简单了. 每次可以向左二分出比x高的第一个楼a,同理也可以向右二分出另一个楼b,如果a,b都存在,答案就是b-a-1. 注意到二分是可以直接在线段树上进行的,所以复杂度是O(nlogn). 当然这里是用分块做的,更暴力一些. #include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace st

51nod1287(二分/线段树区间最值&amp;单点更新)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1287 题意:中文题诶- 解法1:b[i] 存储 max(a[0], ....., a[i]),显然 b 是单调不减的,所以直接二分 x,再更新 a 和 b 数组即可: 代码: 1 #include <iostream> 2 #include <stdio.h> 3 using namespace std; 4 5 const int MAXN =

BZOJ 2527 Poi2011 Meteors 整体二分+线段树 / 可持久化线段树(MLE)

题目大意:给定一个环,每个节点有一个所属国家,k次事件,每次对[l,r]区间上的每个点点权加上一个值,求每个国家最早多少次操作之后所有点的点权和能达到一个值 首先我们考虑暴力想法 对于每个国家分开讨论 二分操作次数 但是这样每次Judge的时候我们要模拟1~mid所有的操作 浪费在这里的复杂度实在太大 这样做每个国家需要模拟O(klogk)次操作 时间复杂度O(nklogk) TLE 我们需要对浪费在这里的复杂度做一些改进 1.可持久化线段树(MLE) 每次二分一个mid之后 我们要找到mid次

poj1201(二分+线段树)或(差分约束系统)

题意:数轴上每个位置为0或是1,给n(1 <= n <= 50000)个区间[ai, bi],每个区间内至少有 ci 个1.0 <= ai <= bi <= 50000,1 <= ci <= bi - ai+1.问数轴上至少有多少个1可以满足要求. 解法1:现将区间按右端点排序,然后每个区间内的点尽量往右边放,这样子可以照顾到以后的.在找每个区间的放法时,线段树查询区间1的个数,二分查找要放的后缀位置,然后将整个区间后缀全部涂上1.总复杂度是nlognlogn.网