[Zjoi2013]K大数查询【树套树】【整体二分】

树套树
算是树套树的模板题吧。。洛谷上吸氧才能过。。(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;
}

猜你喜欢

转载自blog.csdn.net/qq_39921637/article/details/96361630