zoukankan      html  css  js  c++  java
  • K大数查询[ZJOI2013]

    【题目描述】

    你需要维护 (n) 个可重整数集,集合的编号从 (1)(n)

    这些集合初始都是空集,有 (m) 个操作:

    • 1 l r c:表示将 (c) 加入到编号在 ([l,r]) 内的集合中
    • 2 l r c:表示表示查询编号在 ([l,r]) 内的集合的并集(可重)中,第 (c) 大的数是多少。

    【输入/输出格式】

    不关心

    (1 le n,m le 5 imes 10^4), (1le l,r le n), (1) 操作中 (|c|le n), (2) 操作中 (1le c < 2^{63})

    题解

    暴力树套树

    外层维护权值线段树 内层是区间修改线段树

    每次修改就把包含(c)的那些权值线段树节点上的 每个内层线段树的([l,r])区间(+1)

    查询就在权值线段树上二分。。。

    虽然要区间修改 但是空间其实是不会爆的 一次修改其实最多会新建(log^2 n)个内层线段树节点(并不会证明)

    时间复杂度似乎是(O(mlog^2 n))

    p.s. (c)可能是负数 注意要加一个偏移量

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') f = -1;
    	for (; ch <= '9' && ch >= '0'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ '0');
    	return x * f;
    }
    
    int n, m;
    
    //内层线段树 
    
    struct tree{
    	int lc, rc, sum, tag;
    } tr[15000005];
    int tot;
    
    inline void add(int ind, int l, int r, int v) {
    	tr[ind].sum += (r - l + 1) * v;
    	tr[ind].tag += v;
    }
    
    inline void pushdown(int ind, int l, int r) {
    	if (!tr[ind].tag) return;
    	int mid = (l + r) >> 1;
    	if (!tr[ind].lc) tr[ind].lc = ++tot;
    	add(tr[ind].lc, l, mid, tr[ind].tag);
    	if (!tr[ind].rc) tr[ind].rc = ++tot;
    	add(tr[ind].rc, mid + 1, r, tr[ind].tag);
    	tr[ind].tag = 0;
    }
    
    void update(int &ind, int l, int r, int x, int y) {
    	if (!ind) ind = ++tot;
    	if (x <= l && r <= y) {
    		add(ind, l, r, 1);
    		return;
    	}
    	pushdown(ind, l, r);
    	int mid = (l + r) >> 1;
    	if (x <= mid) update(tr[ind].lc, l, mid, x, y);
    	if (mid < y) update(tr[ind].rc, mid+1, r, x, y);
    	tr[ind].sum = (tr[tr[ind].lc].sum + tr[tr[ind].rc].sum);
    }
    
    int query(int ind, int l, int r, int x, int y) {
    	if (!ind) return 0;
    	if (x <= l && r <= y) return tr[ind].sum;
    	pushdown(ind, l, r);
    	int mid = (l + r) >> 1, ret = 0;
    	if (x <= mid) ret += query(tr[ind].lc, l, mid, x, y);
    	if (mid < y) ret += query(tr[ind].rc, mid+1, r, x, y);
    	return ret;
    }
    
    //外层线段树 
    
    struct Tree{
    	int lc, rc;
    } Tr[200005];
    int Rt, Tot, rt[200005];
    
    void Update(int &ind, int l, int r, int x, int y, int pos) {
    	if (!ind) ind = ++Tot;
    	update(rt[ind], 1, n, x, y);
    	if (l == r) return;
    	int mid = (l + r) >> 1;
    	if (pos <= mid) Update(Tr[ind].lc, l, mid, x, y, pos);
    	else Update(Tr[ind].rc, mid+1, r, x, y, pos); 
    }
    
    int Query(int ind, int l, int r, int x, int y, int k) {
    	if (l == r) return l;
    	int mid = (l + r) >> 1;
    	int cnt = query(rt[Tr[ind].rc], 1, n, x, y);
    	if (k <= cnt) return Query(Tr[ind].rc, mid+1, r, x, y, k);
    	else return Query(Tr[ind].lc, l, mid, x, y, k - cnt);
    } 
    
    int main() {
    	n = read(), m = read();
    	for (int i = 1, tp, a, b, c; i <= m; i++) {
    		tp = read(), a = read(), b = read(), c = read();
    		if (tp == 1) {
    			Update(Rt, 0, n<<1, a, b, c + n);
    		} else {
    			int ans = Query(Rt, 0, n<<1, a, b, c);
    			printf("%d
    ", ans - n);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Vue
    前端笔试、面试题
    npm下载文件临时目录、实际存放目录路劲
    ES6
    Electron – 基础学习(3): 项目打包成exe桌面应用 之electron-builder
    Electron+Vue – 基础学习(2): 项目打包成exe桌面应用
    Electron+Vue – 基础学习(1): 创建项目
    软件需求膨胀系数
    职业女性确实处于劣势吗?记一次不甚严谨的考据 -- 向胡适之先生的遥远致敬
    15篇干货博客 38本书 4门公开课 减掉20斤体重 我的2014总结
  • 原文地址:https://www.cnblogs.com/ak-dream/p/AK_DREAM70.html
Copyright © 2011-2022 走看看