luogu P2617 Dynamic Rankings(分块,n <= 1e4)

嘟嘟嘟

带修改区间第k大。

然而某谷把数据扩大到了1e5,所以用分块现在只能得50分。

分块怎么做呢?很暴力的。

基本思想还是块内有序,块外暴力统计。

对于修改,直接重排修改的数所在块,时间复杂度O(√nlogn√n)。

对于询问,二分答案,然后在每个块内再二分统计小于mid的数有几个,块外暴力统计,时间复杂度O(m * log1e9 * √nlog√n),所以只能过1e4。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cctype>
  8 #include<vector>
  9 #include<stack>
 10 #include<queue>
 11 using namespace std;
 12 #define enter puts("")
 13 #define space putchar(‘ ‘)
 14 #define Mem(a, x) memset(a, x, sizeof(a))
 15 #define rg register
 16 typedef long long ll;
 17 typedef double db;
 18 const int INF = 0x3f3f3f3f;
 19 const db eps = 1e-8;
 20 const int maxn = 1e5 + 5;
 21 const int maxb = 320;
 22 inline ll read()
 23 {
 24   ll ans = 0;
 25   char ch = getchar(), last = ‘ ‘;
 26   while(!isdigit(ch)) {last = ch; ch = getchar();}
 27   while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - ‘0‘; ch = getchar();}
 28   if(last == ‘-‘) ans = -ans;
 29   return ans;
 30 }
 31 inline void write(ll x)
 32 {
 33   if(x < 0) x = -x, putchar(‘-‘);
 34   if(x >= 10) write(x / 10);
 35   putchar(x % 10 + ‘0‘);
 36 }
 37
 38 int n, q, a[maxn];
 39 char c[2];
 40
 41 int S, Cnt = 0, blo[maxn], lb[maxn], rb[maxn];
 42 int b[maxb][maxb];
 43 void init()
 44 {
 45   S = sqrt(n);
 46   Cnt = n % S ? n / S + 1: n / S;
 47   for(rg int i = 1; i <= Cnt; ++i) lb[i] = rb[i - 1] + 1, rb[i] = lb[i] + S - 1;
 48   rb[Cnt] = n;
 49   for(rg int i = 1, j = 1; i <= n; ++i) blo[i] = j, j += (i == rb[j]);
 50   for(rg int i = 1, cb = 0; i <= Cnt; ++i, cb = 0)
 51     {
 52       for(rg int j = lb[i]; j <= rb[i]; ++j) b[i][++cb] = a[j];
 53       sort(b[i] + 1, b[i] + cb + 1);
 54     }
 55 }
 56 inline void update(const int& x, const int& k)
 57 {
 58   a[x] = k;
 59   int t = blo[x], cb = 0;
 60   for(rg int i = lb[t]; i <= rb[t]; ++i) b[t][++cb] = a[i];
 61   sort(b[t] + 1, b[t] + cb + 1);
 62 }
 63 inline int judge(const int& L, const int& R, const int& x, const int& k)
 64 {
 65   int l = blo[L], r = blo[R], ret = 0;
 66   if(l == r)
 67     {
 68       for(rg int i = L; i <= R; ++i) ret += (a[i] < x);
 69       return ret < k;
 70     }
 71   for(rg int i = l + 1; i < r; ++i)
 72     {
 73       int tp = lower_bound(b[i] + 1, b[i] + rb[i] - lb[i] + 2, x) - b[i] - 1;
 74       if(tp < 1) tp = 0;
 75       if(tp > rb[i] - lb[i]) tp = rb[i] - lb[i] + 1;
 76       ret += tp;
 77     }
 78   for(rg int i = L; i <= rb[l]; ++i) ret += (a[i] < x);
 79   for(rg int i = lb[r]; i <= R; ++i) ret += (a[i] < x);
 80   return ret < k;
 81 }
 82
 83 int main()
 84 {
 85   n = read(), q = read();
 86   for(rg int i = 1; i <= n; ++i) a[i] = read();
 87   init();
 88   for(rg int i = 1; i <= q; ++i)
 89     {
 90       scanf("%s", c);
 91       if(c[0] == ‘C‘)
 92     {
 93       int x = read(), y = read();
 94       update(x, y);
 95     }
 96       else
 97     {
 98       int L = read(), R = read(), k = read();
 99       int l = 0, r = 1e9;
100       while(l < r)
101         {
102           int mid = (l + r + 1) >> 1;
103           if(judge(L, R, mid, k)) l = mid;
104           else r = mid - 1;
105         }
106       write(l), enter;
107     }
108     }
109   return 0;
110 }

原文地址:https://www.cnblogs.com/mrclr/p/9870719.html

时间: 2024-10-09 15:07:02

luogu P2617 Dynamic Rankings(分块,n <= 1e4)的相关文章

[luogu] P2617 Dynamic Rankings

整体二分模板,所谓整体二分其实就是将修改与询问保存下来,然后二分值域: 树套树亦可,但是码量较大: #include <iostream> #include <cstdio> #include <algorithm> using namespace std;const int N=1e5+7;typedef long long ll; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||

P2617 Dynamic Rankings

题目链接:https://www.luogu.org/problem/P2617 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题.你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令. 对于每一个询问指令,你必

P2617 Dynamic Rankings(带修主席树)

所谓带修主席树,就是用树状数组的方法维护主席树的前缀和 思路 带修主席树的板子 注意数据范围显然要离散化即可 代码 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct Node{ int sz,lson,rson; }PT[100100*400]; struct Q{ char c; int l,r,x,val; }opt[100100]; const

P2617 Dynamic Rankings(主席树+树状数组)

怕是还没有题解,所以先写一篇. 这题就是维护带修改的主席树.首先树套树肯定是能做的,既然树套树能做那么整体二分肯定也是可以的. 由于我并没有使用这两种做法,所以此处不予介绍. 大概描述下主席树的思路: 首先说说怎么搞带修改主席树? 回忆一般的kth问题,我们的主席树求的是前缀和,这样我们在目标区间的左右端点的主席树差分下就能求出kth. 那么我们如何支持修改操作? 考虑到我们之前使用主席树朴素的维护区间前缀和,支持修改的话,只要把前缀和交给擅长它的树状数组维护,主席树只要维护下位置就好. 1 #

P2617 Dynamic Rankings (动态开点权值线段树 + 树状数组)

题意:带修求区间k小 题解:回忆在使用主席树求区间k小时 利用前缀和的思想 既然是前缀和 那么我们可以使用更擅长维护前缀和的树状数组 但是这里每一颗权值线段树就不是带版本的 而是维护数组里i号点的权值信息 所以实际上并不是主席树 每一棵和前面一棵并没有共用结点 对于一次修改操作 我们先删去这个点的原信息 再更新进去 树状数组上的点一起跳 可能看代码比较好理解一点 这个方法限制性也很强 必须离线 #include <bits/stdc++.h> using namespace std; cons

ZOJ 2112 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

BZOJ 1901 Dynamic Rankings

题面: 1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 8088  Solved: 3364[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1 ],a[i+2]--a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变

1901: Zju2112 Dynamic Rankings

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5268  Solved: 2207[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i

【BZOJ-1901】Dynamic Rankings 带修主席树

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7292  Solved: 3038[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i