zoukankan      html  css  js  c++  java
  • 洛谷 P2824 [HEOI2016/TJOI2016]排序

    Description

    洛谷传送门

    Solution

    一眼就能想到线段树,但是线段树似乎也无法维护啊?那怎么做?

    于是我们查看标签……

    发现……二分答案?这怎么二分答案??

    于是我们再回想一下题目要求计算什么:位置是 (q) 的数是多少。

    而且只有一次询问。

    既然是二分答案,那我们就二分呗。

    假设答案是 (mid),那现在的问题就是判断 (mid) 是不是操作完之后是第 (q) 个数。

    考虑到线段树只能进行区间维护,比如区间加,区间修改,区间求和什么的……

    诶,等等,如果我们把小于 (mid) 的数都重新赋值为 0,大于等于 (mid) 的数都赋值为 1,那这个排序是不是就相当于区间赋值了呢?对于从小到大排序,我们不需要知道数到底是多少,只需要把 0 全都放到区间的前半段,1 放到后半段即可。反之同理。

    操作完之后,查询第 (q) 位是 0 还是 1,如果是 0,说明这个 (mid) 太大了,需要调小,反之则需要调大。

    这样一来,这道题就可以完美的解决了,时间复杂度 (O(nlog^2_n))

    最后再讲一下如何区间修改:我们记录一下区间和,那么这个区间和就是区间里 1 的个数,每次修改时先查询一下区间和,然后覆盖即可,具体看代码吧。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define ls rt << 1
    #define rs rt << 1 | 1
    
    using namespace std;
    
    inline int read(){
    	int x = 0;
    	char ch = getchar();
    	while(ch < '0' || ch > '9') ch = getchar();
    	while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    	return x;
    }
    
    const int N = 1e5 + 10;
    int n, m, maxs, p, ans;
    int a[N], sum[N << 2], lazy[N << 2];
    bool b[N];
    struct node{
    	int op, l, r;
    }q[N];
    
    inline void pushup(int rt){
    	sum[rt] = sum[ls] + sum[rs];
    }
    
    inline void pushdown(int l, int r, int rt){
    	if(lazy[rt] != -1){
    		int mid = (l + r) >> 1;
    		sum[ls] = lazy[rt] * (mid - l + 1);
    		sum[rs] = lazy[rt] * (r - mid);
    		lazy[ls] = lazy[rs] = lazy[rt];
    		lazy[rt] = -1;
    	}
    }
    
    inline void build(int l, int r, int rt){
    	lazy[rt] = -1;
    	if(l == r){
    		sum[rt] = b[l];
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(l, mid, ls);
    	build(mid + 1, r, rs);
    	pushup(rt);
    }
    
    inline int query(int L, int R, int l, int r, int rt){
    	if(L <= l && r <= R) return sum[rt];
    	pushdown(l, r, rt);
    	int mid = (l + r) >> 1;
    	int res = 0;
    	if(L <= mid) res += query(L, R, l, mid, ls);
    	if(R > mid) res += query(L, R, mid + 1, r, rs);
    	pushup(rt);
    	return res;
    }
    
    inline void update(int L, int R, int k, int l, int r, int rt){
    	if(L <= l && r <= R){
    		sum[rt] = k * (r - l + 1);
    		lazy[rt] = k;
    		return;
    	}
    	pushdown(l, r, rt);
    	int mid = (l + r) >> 1;
    	if(L <= mid) update(L, R, k, l, mid, ls);
    	if(R > mid) update(L, R, k, mid + 1, r, rs);
    	pushup(rt);
    }
    
    inline bool check(int mid){
    	for(int i = 1; i <= n; i++)
    		b[i] = a[i] >= mid;
    	build(1, n, 1);
    	for(int i = 1; i <= m; i++){
    		int s = query(q[i].l, q[i].r, 1, n, 1);
    		if(!s || s == q[i].r - q[i].l + 1) continue;
    		if(!q[i].op) update(q[i].l, q[i].r - s, 0, 1, n, 1), update(q[i].r - s + 1, q[i].r, 1, 1, n, 1);
    		else update(q[i].l, q[i].l + s - 1, 1, 1, n, 1), update(q[i].l + s, q[i].r, 0, 1, n, 1);
    	}
    	return query(p, p, 1, n, 1);
    }
    
    int main(){
    	n = read(), m = read();
    	for(int i = 1; i <= n; i++)
    		a[i] = read();
    	for(int i = 1; i <= m; i++)
    		q[i].op = read(), q[i].l = read(), q[i].r = read();
    	p = read();
    	int l = 1, r = n;
    	while(l <= r){
    		int mid = (l + r) >> 1;
    		if(check(mid)) ans = mid, l = mid + 1;
    		else r = mid - 1;
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    

    End

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15407265.html

  • 相关阅读:
    车载OS盘点及特点分析一:车载OS几大系统介绍
    CTF常用软件/工具
    汽车软件产业研究报告(2020年)
    高级加密标准(AES)分析
    工具 | CTP、SimNow、NSight、快期
    CTF之图片隐写术解题思路
    V2X和车路协同研究:5G V2X将成为数字座舱标配
    腾讯安全正式发布《IoT安全能力图谱》
    Microsoft Remote Desktop Beta 下载地址
    密码学初探|加密模式
  • 原文地址:https://www.cnblogs.com/xixike/p/15407265.html
Copyright © 2011-2022 走看看