洛谷P3332 第K大数查询 权值线段树内套线段树

传送门

先把所有询问读进来离散化,然后给权值线段树开点,然后对于每个修改操作选择修改logn层的全部信息,用线段树维护信息。

#include <iostream>
#include <cstring>
#include <iomanip>
#include <algorithm>
#include <stack>
#include <queue>
#include <numeric>
#include <cassert>
#include <bitset>
#include <cstdio>
#include <vector>
#include <unordered_set>
#include <cmath>
#include <map>
#include <unordered_map>
#include <set>
#include <deque>
#include <tuple>
#include <array>

#define all(a) a.begin(), a.end()
#define cnt0(x) __builtin_ctz(x)
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define cntone(x) __builtin_popcount(x)
#define db double
#define fs first
#define se second
#define AC main(void)
#define ls(u) tr[u].l
#define rs(u) tr[u].r
#define add(u) tr[u].add
#define sum(u) tr[u].sum
#define HYS std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
typedef std::pair<int, int > PII;
typedef std::pair<int, std::pair<int, int>> PIII;
typedef std::pair<ll, ll> Pll;
typedef std::pair<double, double> PDD;
using ld = double long;

const long double eps = 1e-9;
const int INF = 0x3f3f3f3f;
const int N = 5e4 + 10, M = 6e2 + 10;
int n, m, p;
int a[N], idx;

int d1[] = {0, 0, 1, -1};
int d2[] = {1, -1, 0, 0};

int T[N << 2];

struct node{
	int l, r;
	ll sum, add;
}tr[N * 17 * 17];

inline int get_len(int a, int b, int c, int d){
	return std::min(b, d) - std::max(a, c) + 1;
}

inline void update(int u, int L, int R, int l, int r){
	sum(u) += get_len(L, R, l, r);
	if(L >= l && R <= r){
		add(u) ++;
		return ;
	}
	
	int mid = L + R >> 1;
	if(l <= mid){
		if(!ls(u))	ls(u) = ++ idx;
		update(ls(u), L, mid, l, r);
	}

	if(r > mid){
		if(!rs(u))	rs(u) = ++ idx;
		update(rs(u), mid + 1, R, l, r);
	}
}

inline void modify(int u, int L, int R, int l, int r, int v){//权值线段树修改
	update(T[u], 1, n, l, r);
	if(L == R)	return ;
	int mid = L + R >> 1;
	if(v <= mid)	modify(u << 1, L, mid, l, r, v);
	else modify(u << 1 | 1, mid + 1, R, l, r, v);
}

inline ll get_sum(int u, int L, int R, int l, int r, ll add){
	if(!u)	return add * get_len(L, R, l, r);
	if(L >= l && R <= r)	return add * get_len(L, R, l, r) + sum(u);
	int mid = L + R >> 1;
	ll tot = 0;
	add += add(u);
	
	if(l <= mid)		tot += get_sum(ls(u), L, mid, l, r, add);
	if(r > mid)	tot += get_sum(rs(u), mid + 1, R, l, r, add);
	
	return tot;
}

inline int query(int u, int L, int R, int l, int r, int k){
	if(L == R)	return L;
	ll tot = get_sum(T[u << 1 | 1], 1, n, l, r, 0);
	int mid = L + R >> 1;
	if(tot >= k)	return query(u << 1 | 1, mid + 1, R, l, r, k);
	return query(u << 1, L, mid, l, r, k - tot);
}

inline void solve(){
    std::cin >> n >> m;
	std::vector<std::array<int, 4>> q(m);
	std::vector<int> nums;
	for(int i = 0; i < m; i ++){
		auto &[op, l, r, v] = q[i];
		std::cin >> op >> l >> r >> v;
		if(op == 1)	nums.push_back(v);
	}
	
	std::sort(all(nums));
	nums.erase(std::unique(all(nums)), nums.end());
	int len = nums.size() - 1;
	for(int i = 1; i <= 4 * (len + 1); i ++)	T[i] = ++ idx;//给权值线段树开点
	
	for(int i = 0; i < m; i ++){
		auto &[op, l, r, v] = q[i];
		if(op == 1){
			v = std::lower_bound(all(nums), v) - nums.begin();
			modify(1, 0, len, l, r, v);
		}else{
			std::cout << nums[query(1, 0, len, l, r, v)] << '\n';
		}
	}
}


signed AC{
    HYS

    int _ = 1;
    //std::cin >> _;
    while (_ --)
        solve();

    return 0;
}
posted @ 2023-03-18 22:54  春始于雪之下  阅读(21)  评论(0编辑  收藏  举报