• [ZJOI2013]K大数查询


    权值线段树套线段树模板
    区间每个可重集插入一个数
    把权值放外边,内部维护区间
    在权值线段树上二分,内部查询数量

    ( ext{Code})

    #include <cstdio>
    #include <iostream>
    #define LL long long
    using namespace std;
    
    const int N = 5e4;
    int n, m, rt, seg_size, tr_size;
    struct segment{int ls, rs, tg; LL s;}seg[N * 270 + 5];
    struct tree{int ls, rs, rt;}T[N * 8 + 5];
    
    inline void pushdown(int p, int tl, int tr)
    {
    	if (!seg[p].tg)	return;
    	LL v = seg[p].tg;
    	if (!seg[p].ls) seg[p].ls = ++seg_size; 
    	if (!seg[p].rs) seg[p].rs = ++seg_size;
    	int mid = (tl + tr) >> 1;
    	seg[seg[p].ls].s += v * (mid - tl + 1), seg[seg[p].ls].tg += v;
    	seg[seg[p].rs].s += v * (tr - mid), seg[seg[p].rs].tg += v;
    	seg[p].tg = 0;
    }
    void update(int &p, int tl, int tr, int l, int r)
    {
    	if (!p) p = ++seg_size;
    	seg[p].s += min(tr, r) - max(tl, l) + 1;
    	if (l <= tl && tr <= r) return void(++seg[p].tg);
    	pushdown(p, tl, tr);
    	int mid = (tl + tr) >> 1;
    	if (l <= mid) update(seg[p].ls, tl, mid, l, r);
    	if (r > mid) update(seg[p].rs, mid + 1, tr, l, r);
    }
    LL query(int p, int tl, int tr, int l, int r)
    {
    	if (!p || (l <= tl && tr <= r)) return seg[p].s;
    	pushdown(p, tl, tr);
    	int mid = (tl + tr) >> 1; LL res = 0;
    	if (l <= mid) res = query(seg[p].ls, tl, mid, l, r);
    	if (r > mid) res += query(seg[p].rs, mid + 1, tr, l, r);
    	return res;
    }
    
    void Update(int &p, int tl, int tr, int l, int r, LL k)
    {
    	if (!p) p = ++tr_size;
    	update(T[p].rt, 1, n, l, r);
    	if (tl == tr) return;
    	int mid = (tl + tr) >> 1;
    	if (k <= mid) Update(T[p].ls, tl, mid, l, r, k);
    	else Update(T[p].rs, mid + 1, tr, l, r, k);
    }
    int Query(int p, int tl, int tr, int l, int r, LL k)
    {
    	if (tl == tr) return tl;
    	int mid = (tl + tr) >> 1;
    	LL sum = query(T[T[p].rs].rt, 1, n, l, r);
    	if (k <= sum) return Query(T[p].rs, mid + 1, tr, l, r, k);
    	return Query(T[p].ls, tl, mid, l, r, k - sum);
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	int l, r, op; LL k;
    	for(; m; --m)
    	{
    		scanf("%d%d%d%lld", &op, &l, &r, &k);
    		if (op == 1) Update(rt, -n, n, l, r, k);
    		else printf("%d
    ", Query(rt, -n, n, l, r, k));
    	}
    }
    

    整体二分的话就很套路了
    维护用的数据结构改成区间加操作的线段树即可
    注意划分时的答案范围

    (Code)

    #include <cstdio>
    #include <iostream>
    #define ls (p << 1)
    #define rs (ls | 1)
    #define re register
    #define LL long long
    using namespace std;
    
    const int N = 5e4 + 5;
    int n, m, tot, ans[N];
    struct node{int op, l, r, id; LL k;}Q[N], q1[N], q2[N];
    
    LL seg[N * 4], tag[N * 4];
    inline void pushdown(int p, int l, int r)
    {
    	if (!tag[p]) return;
    	int mid = (l + r) >> 1;
    	seg[ls] += tag[p] * (mid - l + 1), tag[ls] += tag[p];
    	seg[rs] += tag[p] * (r - mid), tag[rs] += tag[p];
    	tag[p] = 0;
    }
    void update(int p, int l, int r, int tl, int tr, int v)
    {
    	seg[p] += (min(r, tr) - max(l, tl) + 1) * v;
    	if (tl <= l && r <= tr) return void(tag[p] += v);
    	pushdown(p, l, r);
    	int mid = (l + r) >> 1;
    	if (tl <= mid) update(ls, l, mid, tl, tr, v);
    	if (tr > mid) update(rs, mid + 1, r, tl, tr, v);
    }
    LL query(int p, int l, int r, int tl, int tr)
    {
    	if (tl <= l && r <= tr) return seg[p];
    	pushdown(p, l, r);
    	int mid = (l + r) >> 1; LL res = 0;
    	if (tl <= mid) res = query(ls, l, mid, tl, tr);
    	if (tr > mid) res += query(rs, mid + 1, r, tl, tr);
    	return res;
    }
    
    void solve(int l, int r, int ql, int qr)
    {
    	if (ql > qr) return;
    	if (l == r)
    	{
    		for(re int i = ql; i <= qr; i++)
    		if (Q[i].op == 2) ans[Q[i].id] = l;
    		return;
    	}
    	int ct1 = 0, ct2 = 0, mid = (l + r) >> 1;
    	for(re int i = ql; i <= qr; i++)
    	{
    		if (Q[i].op == 1) 
    		{
    			if (Q[i].k > mid) update(1, 1, n, Q[i].l, Q[i].r, 1), q1[++ct1] = Q[i];
    			else q2[++ct2] = Q[i];
    		}
    		else{
    			LL sum = query(1, 1, n, Q[i].l, Q[i].r);
    			if (Q[i].k <= sum) q1[++ct1] = Q[i];
    			else Q[i].k -= sum, q2[++ct2] = Q[i];
    		}
    	}
    	for(re int i = 1; i <= ct1; i++)
    	if (q1[i].op == 1) update(1, 1, n, q1[i].l, q1[i].r, -1);
    	for(re int i = 1; i <= ct1; i++) Q[ql + i - 1] = q1[i];
    	for(re int i = 1; i <= ct2; i++) Q[ql + ct1 - 1 + i] = q2[i];
    	solve(mid + 1, r, ql, ql + ct1 - 1), solve(l, mid, ql + ct1, qr);
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	int op, l, r; LL k;
    	for(re int i = 1; i <= m; i++)
    	{
    		scanf("%d%d%d%lld", &Q[i].op, &Q[i].l, &Q[i].r, &Q[i].k);
    		if (Q[i].op == 2) Q[i].id = ++tot;
    	}
    	solve(-n, n, 1, m);
    	for(re int i = 1; i <= tot; i++) printf("%d
    ", ans[i]);
    }
    

    发现树套树好像更好打(又短)
    但整体二分跑得是真的快

  • 相关阅读:
    Netty ByteBuf(图解之 2)| 秒懂
    【转】 RGB各种格式
    缺少动态库报错
    bug:进程可调用函数而子线程调用报错
    【转】 pthread设置线程的调度策略和优先级
    【转】 C++析构函数的作用和用法
    【转】 g++编译时对'xxxx'未定义的引用问题(undefined reference to)
    【转】 C语言文件操作详解
    【转】 H.264编码原理以及I帧B帧P帧
    【转】 strrchr()函数---C语言
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/15369477.html
Copyright © 2020-2023  润新知