ZOJ 1112 Dynamic Rankings【动态区间第K大,整体二分】

题目链接:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112

题意:

求动态区间第K大。

分析:

把修改操作看成删除与增加,对所有操作进行整体二分。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define pr(x) cout << #x << ": " << x << "  "
#define pl(x) cout << #x << ": " << x << endl;
const int maxn = 50000 + 5, maxq = 20000 + 5, oo = 0x3f3f3f3f;
int n, m, tot;
int a[maxn];
struct Query{
    int x, y, k;
    int id, type;
}q[maxn + maxq], q1[maxn + maxq], q2[maxn + maxq];
int bit[maxn];
int ans[maxq];
void add(int i, int x)
{
    while(i <= n){
        bit[i] += x;
        i += i & -i;
    }
}
int sum(int i)
{
    int ans = 0;
    while(i > 0){
        ans += bit[i];
        i -= i & -i;
    }
    return ans;
}
void solve(int ql, int qr, int l, int r)
{
    if(ql > qr) return ;
    if(l == r){
        for(int i = ql; i <= qr; i++){
            if(q[i].type == 2) ans[q[i].id] = l;
        }
        return ;
    }
    int t1 = 0, t2 = 0;
    int mid = l + r >> 1;
   // pl(mid);
    for(int i = ql; i <= qr; i++){
        if(q[i].type == 1){
            if(q[i].x <= mid){
                add(q[i].id, q[i].y);
                q1[t1++] = q[i];
            }else q2[t2++] = q[i];
        }else{
            int tmp = sum(q[i].y) -sum(q[i].x - 1);
            if(tmp >= q[i].k) q1[t1++] = q[i];
            else {
                    q[i].k -= tmp;
                    q2[t2++] = q[i];
            }
        }
    }
    for(int i = 0; i < t1; i++){
        if(q1[i].type == 1) add(q1[i].id, -q1[i].y);
    }
    for(int i = 0; i < t1; i++) q[ql + i] = q1[i];
    for(int i = 0; i < t2; i++) q[t1 + i + ql] = q2[i];

    solve(ql, ql + t1 - 1, l, mid);
    solve(ql + t1, qr, mid + 1, r);
}
int main (void)
{
    int x;scanf("%d", &x);
    while(x--){
        scanf("%d%d", &n, &m);
        tot = 0;
        memset(bit, 0, sizeof(bit));
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
            q[++tot] = (Query){a[i], 1, oo, i, 1};
        }
        char s[2];
        int x, y, k;
        int cnt = 0;
        for(int i = 1; i <= m; i++){
            scanf("%s%d%d", s, &x, &y);
            if(s[0] == ‘Q‘){
                scanf("%d", &k);
                q[++tot] = (Query){x, y, k, ++cnt, 2};
            }else{
                q[++tot] = (Query){a[x], -1, oo, x, 1};
                q[++tot] = (Query){y, 1, oo, x, 1};
            }
        }
        solve(1, tot, 0, oo);
        for(int i = 1; i <= cnt; i++){
            printf("%d\n", ans[i]);
        }
    }
    return 0;
}
时间: 2024-10-10 20:02:09

ZOJ 1112 Dynamic Rankings【动态区间第K大,整体二分】的相关文章

zoj2112 Dynamic Rankings 动态区间第k大,树状数组套平衡树

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int

ZOJ2112--Dynamic Rankings (动态区间第k大)

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They

zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap

Dynamic Rankings Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 Description The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query l

BZOJ 1901 Zju 2112 Dynamic Rankings 动态维护第k小 树套树

题目大意:动态维护第k小. 思路:线段树套treap,裸题,就是不怎么好写. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 50010 #define INF 1e9 #define LEFT (pos << 1) #define RIGHT (pos << 1|1) #define SIZ

【XSY2720】区间第k小 整体二分 可持久化线段树

题目描述 给你你个序列,每次求区间第\(k\)小的数. 本题中,如果一个数在询问区间中出现了超过\(w\)次,那么就把这个数视为\(n\). 强制在线. \(n\leq 100000,a_i<n,w\leq n\) 题解 考虑整体二分. 先看看离线要怎么做. 现在我们要计算每个数对每个区间的贡献. 对于每个询问区间和每种数,让这个区间最右边\(w\)个数对这个询问的贡献为\(1\),第\(w+1\)个数对这个询问的贡献为\(-w\). 这样每个数的贡献就是二维平面上的一个矩形.可以用扫描线+线段

静态区间第k小 - 整体二分

蒟蒻终于学会整体二分啦! 思路 实现 丑陋无比的代码 #include <bits/stdc++.h> using namespace std; const int N = 200005; int ar[N]; int lowbit(int t) { return t & (-t); } void add(int i, int v) { for (; i < N; ar[i] += v, i += lowbit(i)); } int sum(int i) { int s = 0;

hdu 5412 CRB and Queries(线段树套笛卡尔树 - 动态区间第k大)

题目链接:hdu 5412 CRB and Queries 首先对所有出现过的值排序,建立线段树,每个线段树的节点是一棵笛卡尔树,笛卡尔树记录区间下标值. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; #define lson(x) (x<<1) #define rson(x) ((x<<

整体二分求动态区间第k大

比树状数组套主席树不知道高到哪里去了,solve(l,r,L,R)就是对于L,R的操作区间的答案都在l,r区间里,然后递归下去 复杂度O(nlognlogn),每个操作会执行logn次就是o(nlogn),带上bit就是loglogn //#pragma GCC optimize(2) //#pragma GCC optimize(3) //#pragma GCC optimize(4) //#pragma GCC optimize("unroll-loops") //#pragma

zoj 2112 Dynamic Rankings(主席树&amp;动态第k大)

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They