洛谷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;
}