算是树套树的模板题吧。。洛谷上吸氧才能过。。(BZOJ会T23333)因为离散用了vector和lower_bound。。
外层权值线段树,内层普通区间线段树
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e7+5;
const int mx = 5e5+5;
typedef long long ll;
const ll mod = 1e9+7;
int Case = 1;
int n, m;
int ch[maxn][2];
ll sum[maxn];
int lazy[maxn], tot;
void pushup(int rt) {
sum[rt] = sum[ch[rt][0]] + sum[ch[rt][1]];
}
void pushdown(int rt, int l, int r) {
if(lazy[rt]) {
int mid = (l+r)/2;
if(!ch[rt][0]) ch[rt][0] = ++tot;
if(!ch[rt][1]) ch[rt][1] = ++tot;
assert(tot < maxn);
lazy[ch[rt][0]] += lazy[rt];
lazy[ch[rt][1]] += lazy[rt];
sum[ch[rt][0]] += 1ll * lazy[rt] * (mid-l+1);
sum[ch[rt][1]] += 1ll * lazy[rt] * (r-mid);
lazy[rt] = 0;
}
}
void update(int &rt, int L, int R, int l, int r) {
if(!rt) rt = ++tot;
assert(tot < maxn);
if(L == l && R == r) {
lazy[rt]++;
sum[rt] += R-L+1;
return;
}
pushdown(rt, L, R);
int mid = (R+L)/2;
if(r <= mid) update(ch[rt][0], L, mid, l, r);
else if(l > mid) update(ch[rt][1], mid+1, R, l, r);
else update(ch[rt][0], L, mid, l, mid), update(ch[rt][1], mid+1, R, mid+1, r);
pushup(rt);
}
ll query(int rt, int L, int R, int l, int r) {
if(!rt) return 0;
if(L == l && R == r) {
return sum[rt];
}
pushdown(rt, L, R);
int mid = (R+L)/2;
if(r <= mid) return query(ch[rt][0], L, mid, l, r);
else if(l > mid) return query(ch[rt][1], mid+1, R, l, r);
else return query(ch[rt][0], L, mid, l, mid) + query(ch[rt][1], mid+1, R, mid+1, r);
}
int root[maxn];
void insert(int a, int b, int pos) {
int l = 1, r = n, rt = 1;
while(l != r) {
int mid = (l + r)/2;
update(root[rt], 1, n, a, b);
if(pos <= mid) rt = rt*2, r = mid;
else rt = rt*2+1, l = mid+1;
}
update(root[rt], 1, n, a, b);
}
int query(int a, int b, ll k) {
int l = 1, r = n, rt = 1;
while(l != r) {
int mid = (l + r)/2;
ll sum = query(root[rt*2], 1, n, a, b);
if(sum >= k) r = mid, rt = rt*2;
else l = mid+1, k -= sum, rt = rt*2+1;
}
return l;
}
struct node{
int op, a, b;ll c;
}cc[mx];
vector<int>ve;
int getid(int x) {
return lower_bound(ve.begin(), ve.end(), x)-ve.begin()+1;
}
template<class T>
void read(T& x) {
int f = 1; x = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1;ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}
x *= f;
}
void solve() {
read(n);read(m);
for(int i = 1; i <= m; i++) {
read(cc[i].op);read(cc[i].a);
read(cc[i].b);read(cc[i].c);
if(cc[i].op == 1) ve.push_back(cc[i].c);
}
sort(ve.begin(), ve.end());
ve.erase(unique(ve.begin(), ve.end()), ve.end());
//n = ve.size();
for(int i = 1; i <= m; i++) {
int op, a, b;ll c;
op = cc[i].op;a = cc[i].a;
b=cc[i].b;c=cc[i].c;
if(op == 1) insert(a, b, getid(c));
else printf("%d\n", ve[query(a, b, c)-1]);
}
return;
}
int main() {
//g++ -std=c++11 -o2 1.cpp -o f && ./f < in.txt
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
while(Case--) {
solve();
}
return 0;
}
(不用离散化,不用开很大空间,整体二分你值得拥有。
这道题和这道题很像只不过单点修改改成了区间更新,用线段树搞一下就行了(虽然树状数组用差分也可以维护区间信息,但一直没搞懂。。。)
注意一下细节就行了。。。
查询第k大可以把所有的修改的值改成负的,然后查k小,随后输出的时候加个负号就行了。
对了。。。这份代码交洛谷能过,bzoj也不能过,CE!我服了。
#pragma GCC optimize(2)
#include<cstdio>
using namespace std;
const int maxn = 5e6+5;
typedef long long ll;
const ll mod = 1e9+7;
int Case = 1;
int n, m;
struct Tree{
ll sum[maxn];
int lazy[maxn], ch[maxn][2], tot, root;
int newnode() {
return ++tot;
}
void pushdown(int rt, int L, int R) {
if(lazy[rt]) {
int mid = (R+L)/2;
int &x = lazy[rt];
if(!ch[rt][0]) ch[rt][0] = newnode();
if(!ch[rt][1]) ch[rt][1] = newnode();
lazy[ch[rt][0]] += x;
lazy[ch[rt][1]] += x;
sum[ch[rt][0]] += 1ll*x*(mid-L+1);
sum[ch[rt][1]] += 1ll*x*(R-mid);
x = 0;
}
}
void pushup(int rt) {
sum[rt] = sum[ch[rt][0]] + sum[ch[rt][1]];
}
void update(int &rt, int L, int R, int l, int r, int val) {
if(!rt) rt = newnode();
if(l == L && r == R) {
sum[rt] += 1ll*val*(R-L+1);
lazy[rt] += val;
return;
}
pushdown(rt, L, R);
int mid = (L+R)/2;
if(r <= mid) update(ch[rt][0], L, mid, l, r, val);
else if(l > mid) update(ch[rt][1], mid+1, R, l, r, val);
else update(ch[rt][0], L, mid, l, mid, val), update(ch[rt][1], mid+1, R, mid+1, r, val);
pushup(rt);
}
ll query(int rt, int L, int R, int l, int r) {
if(!rt) return 0;
if(L == l && R == r) {
return sum[rt];
}
pushdown(rt, L, R);
int mid = (L+R)/2;
if(r <= mid) return query(ch[rt][0], L, mid, l, r);
else if(l > mid) return query(ch[rt][1], mid+1, R, l, r);
else return query(ch[rt][0], L, mid, l, mid) + query(ch[rt][1], mid+1, R, mid+1, r);
}
}tree;
int res[maxn];
struct node{
int op, a, b, pos;
ll k;
}cc[maxn], t1[maxn], t2[maxn];
void cal(int L, int R, int l, int r) {
if(L > R || l > r) return;
if(L == R) {
for(int i = l; i <= r; i++) if(cc[i].op == 2) res[cc[i].pos] = -L;
return;
}
ll mid = (L+R)>>1, cnt1 = 0, cnt2 = 0;
for(int i = l; i <= r; i++) {
if(cc[i].op == 2) {
ll sum = tree.query(tree.root, 1, n, cc[i].a, cc[i].b);
if(sum >= cc[i].k) t1[++cnt1] = cc[i];
else cc[i].k -= sum, t2[++cnt2] = cc[i];
}
else {
if(cc[i].k <= mid) tree.update(tree.root, 1, n, cc[i].a, cc[i].b, 1), t1[++cnt1] = cc[i];
else t2[++cnt2] = cc[i];
}
}
for(int i = 1; i <= cnt1; i++) if(t1[i].op == 1) tree.update(tree.root, 1, n, t1[i].a, t1[i].b, -1);
for(int i = 1; i <= cnt1; i++) cc[l+i-1] = t1[i];
for(int i = 1; i <= cnt2; i++) cc[l+cnt1+i-1] = t2[i];
cal(L, mid, l, l+cnt1-1);cal(mid+1, R, l+cnt1, r);
}
void solve() {
scanf("%d%d", &n, &m);
int cnt = 0;
for(int i = 1; i <= m; i++) {
scanf("%d%d%d%lld", &cc[i].op, &cc[i].a, &cc[i].b, &cc[i].k);
if(cc[i].op == 2) cc[i].pos = ++cnt;
else cc[i].k = -cc[i].k;
}
cal(-n, n, 1, m);
for(int i = 1; i <= cnt; i++)
printf("%d\n", res[i]);
return;
}
int main() {
//g++ -std=c++11 -o2 1.cpp -o f && ./f < in.txt
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
while(Case--) {
solve();
}
return 0;
}