给出一个序列,求区间第k小。要求支持单点修改。
不谈修改的时候,地球人都会做。
主要考虑如何维护修改。如果直接在建好的线段树上修改,每次需要新建 O(n) 棵线段树,显然吃不消。
请诸君一定要有一个思想,所谓“函数式线段树”,本质是“化‘树’为‘数’”,让“线段树”这一复杂的结构变得像“数字”一样可以加加减减。为什么区间第k大要用主席树做?因为我们要求区间内小于某一个数的数字个数。这显然是可加的。我们不如就类比做区间求和。带修改的区间求和如何做?树状数组可做。那树状数组每个节点维护的东西变成主席树,就能维护题目中的修改了。
(不要随便看代码。不要随便看代码。不要随便看代码。重要的事情说三遍。)
指针版:
#ifdef _MSC_VER
# include "stdafx.h"
# pragma warning(disable:4996)
#endif
#include
#include
#include
#include
#include
using namespace std;
//Global Variables & Definitions
#define lowbit(x) ((x) & (-(x)))
int X, M, N;
#define MAXN 50050
#define MAXM 10010
#define MAXT (MAXN + MAXM)
int A[MAXN];
//End Global Variables & Definitions
//Discretization
int w[MAXT];
int wcnt;
void Discre(int cnt) {
sort(w + 1, w + cnt + 1);
wcnt = unique(w + 1, w + cnt + 1) - w - 1;
}
int getid(int ww) {
return lower_bound(w + 1, w + wcnt + 1, ww) - w;
}
//End Discretization
//Chairman Tree
#define DEFINE_MID int mid = (l + r) >> 1
#define lson (u -> lc)
#define rson (u -> rc)
namespace CMT {
struct node {
node *lc, *rc;
int sum;
} T[1750250];
int tcnt = 0;
inline void Init() {
tcnt = 0;
}
inline node* newnode() {
//return new node();
return &T[tcnt++];
}
inline node* Copy(node *u) {
node *temp = newnode();
*temp = *u;
return temp;
}
inline void PushUp(node *u) {
u->sum = lson->sum + rson->sum;
}
void Build(node *u, int l, int r) {
u->sum = 0; u->lc = u->rc = NULL;
if (l == r) return;
DEFINE_MID;
lson = newnode();
Build(lson, l, mid);
rson = newnode();
Build(rson, mid + 1, r);
}
void Insert(node *u, int l, int r, int p, int v = 1) {
if (l == r) { u->sum += v; return; }
DEFINE_MID;
if (p <= mid) {
lson = Copy(lson);
Insert(lson, l, mid, p, v);
}
else {
rson = Copy(rson);
Insert(rson, mid + 1, r, p, v);
}
PushUp(u);
}
int Query(node *u, int l, int r, int p) {
if (p >= r) return u->sum;
DEFINE_MID;
if (p == mid) return lson->sum;
else if (p < mid) return Query(lson, l, mid, p);
else return lson->sum + Query(rson, mid + 1, r, p);
}
}
using CMT::node;
node* root[MAXN];
//End Chairman Tree
//Fenwick Tree
node* ftr[MAXN];
void Modify(int x, int p, int v) {
while (x <= N) {
ftr[x] = CMT::Copy(ftr[x]);
CMT::Insert(ftr[x], 1, wcnt, p, v);
x += lowbit(x);
}
}
int sum(int x, int p) {
int temp = 0;
while (x) {
temp += CMT::Query(ftr[x], 1, wcnt, p);
x -= lowbit(x);
}
return temp;
}
//End Fenwick Tree
//Main Structure
inline int getans(int l, int r, int v) {
int ansa = CMT::Query(root[r], 1, wcnt, v) - CMT::Query(root[l], 1, wcnt, v);
ansa += sum(r, v);
ansa -= sum(l, v);
return ansa;
}
int Query(int l, int r, int k) {
int L = 1, R = wcnt;
while (L < R) {
int mid = (L + R) >> 1;
int tans = getans(l - 1, r, mid);
if (tans >= k) R = mid;
else L = mid + 1;
}
return w[L];
}
char Act[MAXM];
int I[MAXM], J[MAXM], K[MAXM];
void ir() {
//Read
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; ++i) {
scanf("%d", &A[i]);
w[i] = A[i];
}
wcnt = N;
char temp[20]; int ii, jj, kk;
for (int i = 0; i < M; ++i) {
scanf("%s%d", temp, &ii);
if ((Act[i] = temp[0]) == 'Q') {
scanf("%d%d", &jj, &kk);
I[i] = ii;
J[i] = jj;
K[i] = kk;
}
else {
scanf("%d", &jj);
I[i] = ii;
w[++wcnt] = J[i] = jj;
}
}
Discre(wcnt);
//Build
CMT::Init();
root[0] = CMT::newnode();
CMT::Build(root[0], 1, wcnt);
for (int i = 1; i <= N; ++i) {
root[i] = CMT::Copy(root[i - 1]);
CMT::Insert(root[i], 1, wcnt, getid(A[i]));
}
for (int i = 1; i <= N; ++i) ftr[i] = root[0];
}
void solve() {
ir();
for (int i = 0; i < M; ++i) {
if (Act[i] == 'Q') {
printf("%d\n", Query(I[i], J[i], K[i]));
}
else {
Modify(I[i], getid(A[I[i]]), -1);
Modify(I[i], getid(A[I[i]] = J[i]), 1);
}
}
}
inline void g_ir() {
scanf("%d", &X);
}
int main() {
g_ir();
while (X--) solve();
return 0;
}
数组版:
#ifdef _MSC_VER
# include "stdafx.h"
# pragma warning(disable:4996)
#endif
#include
#include
#include
#include
#include
using namespace std;
//Global Variables & Definitions
#define lowbit(x) ((x) & (-(x)))
int X, M, N;
#define MAXN 50050
#define MAXM 10010
#define MAXT (MAXN + MAXM)
int A[MAXN];
//End Global Variables & Definitions
//Discretization
int w[MAXT];
int wcnt;
void Discre(int cnt) {
sort(w + 1, w + cnt + 1);
wcnt = unique(w + 1, w + cnt + 1) - w - 1;
}
int getid(int ww) {
return lower_bound(w + 1, w + wcnt + 1, ww) - w;
}
//End Discretization
//Chairman Tree
#define DEFINE_MID int mid = (l + r) >> 1
#define lson T[u].lc
#define rson T[u].rc
namespace CMT {
struct node {
int lc, rc;
int sum;
} T[2500250];
int tcnt = 0;
inline void Init() {
tcnt = 0;
}
inline int newnode() {
return tcnt++;
}
inline int Copy(int u) {
int temp = newnode();
T[temp] = T[u];
return temp;
}
inline void PushUp(int u) {
T[u].sum = T[lson].sum + T[rson].sum;
}
void Build(int u, int l, int r) {
T[u].sum = 0; T[u].lc = T[u].rc = 0;
if (l == r) return;
DEFINE_MID;
lson = newnode();
Build(lson, l, mid);
rson = newnode();
Build(rson, mid + 1, r);
}
void Insert(int u, int l, int r, int p, int v = 1) {
if (l == r) { T[u].sum += v; return; }
DEFINE_MID;
if (p <= mid) {
lson = Copy(lson);
Insert(lson, l, mid, p, v);
}
else {
rson = Copy(rson);
Insert(rson, mid + 1, r, p, v);
}
PushUp(u);
}
int Query(int u, int l, int r, int p) {
if (p >= r) return T[u].sum;
DEFINE_MID;
if (p == mid) return T[lson].sum;
else if (p < mid) return Query(lson, l, mid, p);
else return T[lson].sum + Query(rson, mid + 1, r, p);
}
}
using CMT::node;
int root[MAXN];
//End Chairman Tree
//Fenwick Tree
int ftr[MAXN];
void Modify(int x, int p, int v) {
while (x <= N) {
ftr[x] = CMT::Copy(ftr[x]);
CMT::Insert(ftr[x], 1, wcnt, p, v);
x += lowbit(x);
}
}
int sum(int x, int p) {
int temp = 0;
while (x) {
temp += CMT::Query(ftr[x], 1, wcnt, p);
x -= lowbit(x);
}
return temp;
}
//End Fenwick Tree
//Main Structure
inline int getans(int l, int r, int v) {
int ansa = CMT::Query(root[r], 1, wcnt, v) - CMT::Query(root[l], 1, wcnt, v);
ansa += sum(r, v);
ansa -= sum(l, v);
return ansa;
}
int Query(int l, int r, int k) {
int L = 1, R = wcnt;
while (L < R) {
int mid = (L + R) >> 1;
int tans = getans(l - 1, r, mid);
if (tans >= k) R = mid;
else L = mid + 1;
}
return w[L];
}
char Act[MAXM];
int I[MAXM], J[MAXM], K[MAXM];
void ir() {
//Read
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; ++i) {
scanf("%d", &A[i]);
w[i] = A[i];
}
wcnt = N;
char temp[20]; int ii, jj, kk;
for (int i = 0; i < M; ++i) {
scanf("%s%d", temp, &ii);
if ((Act[i] = temp[0]) == 'Q') {
scanf("%d%d", &jj, &kk);
I[i] = ii;
J[i] = jj;
K[i] = kk;
}
else {
scanf("%d", &jj);
I[i] = ii;
w[++wcnt] = J[i] = jj;
}
}
Discre(wcnt);
//Build
CMT::Init();
root[0] = CMT::newnode();
CMT::Build(root[0], 1, wcnt);
for (int i = 1; i <= N; ++i) {
root[i] = CMT::Copy(root[i - 1]);
CMT::Insert(root[i], 1, wcnt, getid(A[i]));
}
for (int i = 1; i <= N; ++i) ftr[i] = root[0];
}
void solve() {
ir();
for (int i = 0; i < M; ++i) {
if (Act[i] == 'Q') {
printf("%d\n", Query(I[i], J[i], K[i]));
}
else {
Modify(I[i], getid(A[I[i]]), -1);
Modify(I[i], getid(A[I[i]] = J[i]), 1);
}
}
}
inline void g_ir() {
scanf("%d", &X);
}
int main() {
g_ir();
while (X--) solve();
return 0;
}
(当你看到这里我才会告诉你ZOJ上指针版没有WA但是会MLE)