http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112
提高代码能力。。。
方法一:
线段树套平衡树,时间:O(m*lgn*lgn*lgn),空间:O(n*lgn)。
<pre name="code" class="cpp">#include <iostream> #include <cstdlib> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int MAXN(50010); template<typename T> bool checkmin(T &a, const T &b){ return b < a? (a = b, true): false; } template<typename T> bool checkmax(T &a, const T &b){ return b > a? (a = b, true): false; } struct RAND{ int rn[MAXN], si, n; void init(int n){ this->n = n; srand(2357); for(int i = 0; i < n; ++i) rn[i] = rand(); si = 0; } int query(){ if(si >= n) si -= n; return rn[si++]; } } ra; struct NODE1{ int ke, b, si; NODE1 *ch[2]; } *NIL1; struct POOL1{ NODE1 pool[MAXN*19], *last; void init(){ last = pool; } NODE1 *all(int k){ last->ch[0] = last->ch[1] = NIL1; last->ke = k; last->b = ra.query(); last->si = 1; return last++; } } pool1; inline void rep(NODE1 *rt){ if(rt == NIL1) return; rt->si = rt->ch[0]->si+rt->ch[1]->si+1; } void rot(NODE1 *&rt, int f){ NODE1 *s = rt->ch[f]; rt->ch[f] = s->ch[!f]; s->ch[!f] = rt; rep(rt); rep(s); rt = s; } void Insert(NODE1 *&rt, int k){ if(rt == NIL1){ rt = pool1.all(k); return; } int t = (k >= rt->ke); Insert(rt->ch[t], k); if(rt->ch[t]->b > rt->b) rot(rt, t); rep(rt); } void Erase(NODE1 *&rt, int k){ if(rt->ke == k){ if(rt->ch[0] == NIL1 || rt->ch[1] == NIL1){ rt = rt->ch[rt->ch[0] == NIL1]; // rep(rt); return; } int t = rt->ch[0]->b < rt->ch[1]->b; rot(rt, t); Erase(rt->ch[!t], k); rep(rt); return; } Erase(rt->ch[k >= rt->ke], k); rep(rt); } int Lower_bound(NODE1 *rt, int k){ if(rt == NIL1) return 0; if(k <= rt->ke) return Lower_bound(rt->ch[0], k); return rt->ch[0]->si+1+Lower_bound(rt->ch[1], k); } int arr[MAXN]; NODE1 *srt[MAXN << 2]; int query(int ql, int qr, int k, int l, int r, int rt){ if(srt[rt] == 0){ srt[rt] = NIL1; for(int i = l; i <= r; ++i) Insert(srt[rt], arr[i]); } if(ql <= l && qr >= r) return Lower_bound(srt[rt], k); int m = (l+r)/2, ret = 0; if(ql <= m) ret += query(ql, qr, k, l, m, rt << 1); //小心,不要把qr写成m,考虑[ql, qr]包含于左子树的情况 if(qr > m) ret += query(ql, qr, k, m+1, r, (rt << 1)|1); //小心,不要把ql写成m+1,考虑[ql, qr]包含于右子树的情况 return ret; } void update(int loc, int k, int l, int r, int rt){ if(srt[rt] == 0){ srt[rt] = NIL1; for(int i = l; i <= r; ++i) Insert(srt[rt], arr[i]); } if(l <= loc && loc <= r){ Erase(srt[rt], arr[loc]); Insert(srt[rt], k); } if(l == r) return; int m = (l+r)/2; if(loc <= m) update(loc, k, l, m, rt << 1); else update(loc, k, m+1, r, (rt <<1)|1); } int main(){ ra.init(50000); NIL1 = new NODE1(); NIL1->ch[0] = NIL1->ch[1] = NIL1; NIL1->b = -1; NIL1->si = 0; int TC; scanf("%d", &TC); while(TC--){ int n, M, a, b, c; char s[2]; scanf("%d%d", &n, &M); pool1.init(); memset(srt, 0, sizeof(srt)); int mi = 1000000001, mx = -1; for(int i = 1; i <= n; ++i){ scanf("%d", arr+i); checkmin(mi, arr[i]); checkmax(mx, arr[i]); } for(int i = 0; i < M; ++i){ scanf("%s", s); if(s[0] == 'Q'){ scanf("%d%d%d", &a, &b, &c); int l = mi, r = mx, m, t; while(l <= r){ m = (l+r)/2; t = query(a, b, m, 1, n, 1); if(t < c) l = m+1; else r = m-1; } printf("%d\n", l-1); }else{ scanf("%d%d", &a, &b); update(a, b, 1, n, 1); arr[a] = b; checkmin(mi, b); checkmax(mx, b); } } } return 0; }
分块处理,时间:O(m*sqrtn*lgn*lgn),空间:O(n)
#include <iostream> #include <cstdlib> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; const int MAXN(50010); template<typename T> bool checkmin(T &a, const T &b){ return b < a? (a = b, true): false; } template<typename T> bool checkmax(T &a, const T &b){ return b > a? (a = b, true): false; } int ar1[MAXN], ar2[MAXN]; int main(){ int TC; scanf("%d", &TC); while(TC--){ int n, M, mi = 1000000001, mx = -1; scanf("%d%d", &n, &M); for(int i = 0; i < n; ++i){ scanf("%d", ar1+i); ar2[i] = ar1[i]; checkmin(mi, ar1[i]); checkmax(mx, ar1[i]); } int sq = sqrt(n+1.); for(int i = 0; i < n; i += sq) sort(ar2+i, ar2+min(i+sq, n)); char s[2]; int a, b, c; for(int i = 0; i < M; ++i){ scanf("%s", s); if(s[0] == 'Q'){ scanf("%d%d%d", &a, &b, &c); --a, --b; int li = a/sq, ri = b/sq; int t, m, l = mi, r = mx; while(l <= r){ m = (l+r)/2; t = 0; if(li == ri){ for(int j = a; j <= b; ++j) if(ar1[j] < m) ++t; } else{ for(int j = a; j < sq*(li+1); ++j) if(ar1[j] < m) ++t; for(int j = li+1; j < ri; ++j) t += lower_bound(ar2+j*sq, ar2+(j+1)*sq, m)-(ar2+j*sq); for(int j = sq*ri; j <= b; ++j) if(ar1[j] < m) ++t; } if(t < c) l = m+1; else r = m-1; } printf("%d\n", l-1); } else{ scanf("%d%d", &a, &b); --a; ar1[a] = b; checkmin(mi, b); checkmax(mx, b); int li = (a/sq)*sq, ri = min((a/sq+1)*sq, n); for(int j = li; j < ri; ++j) ar2[j] = ar1[j]; sort(ar2+li, ar2+ri); } } } return 0; }
树状数组套函数式线段树,时间:O((n+m)*lgn*lgn),空间:O((n+m)*lgn*lgn)。
超内存。。。
方法四:
值域线段树套下标线段树,时间:O((n+m)*lgn*lgn),空间:O((n+m)*lgn*lgn)。
超内存。。。,存下代码。
struct NODE{ int dat; NODE *ls, *rs; NODE(){} NODE(int d_, NODE *ls_, NODE *rs_) :dat(d_), ls(ls_), rs(rs_){} void push_up(){ dat = 0; if (ls) dat += ls->dat; if (rs) dat += rs->dat; } }; void update(int l, int r, NODE *&p, int id, int v){ if (p == 0) p = new NODE(0, 0, 0); if (l == r) { p->dat += v; return; } int m = (l + r) / 2; if (id <= m) update(l, m, p->ls, id, v); else update(m + 1, r, p->rs, id, v); p->push_up(); } int query(int l, int r, NODE *&p, int ql, int qr){ if (p == 0) return 0; if (ql <= l && qr >= r) return p->dat; int m = (l + r) / 2, ret = 0; if (ql <= m) ret += query(l, m, p->ls, ql, qr); if (qr > m) ret += query(m + 1, r, p->rs, ql, qr); return ret; } struct NODE1{ NODE *dat; NODE1 *ls, *rs; NODE1(){} NODE1(NODE *d_, NODE1 *ls_, NODE1 *rs_): dat(d_), ls(ls_), rs(rs_){} }; vector<int> rec[MAXM]; int N; inline void pre(NODE1 *&p, int l, int r){ if (p == 0){ p = new NODE1(0, 0, 0); for (int i = l; i <= r; ++i) for (int j = 0; j < rec[i].size(); ++j) update(0, N - 1, p->dat, rec[i][j], 1); } } void update1(int l, int r, NODE1 *&p, int id, int v, int v1){ pre(p, l, r); update(0, N - 1, p->dat, id, v1); if (l == r) return; int m = (l + r) / 2; if (v <= m) update1(l, m, p->ls, id, v, v1); else update1(m + 1, r, p->rs, id, v, v1); } int query1(int l, int r, NODE1 *&p, int ql, int qr, int K){ if (l == r) return l; pre(p, l, r); int m = (l + r) / 2; pre(p->ls, l, m); int temp = query(0, N - 1, p->ls->dat, ql, qr); if (temp >= K) return query1(l, m, p->ls, ql, qr, K); else{ pre(p->rs, m + 1, r); return query1(m + 1, r, p->rs, ql, qr, K-temp); } } int arr[MAXN]; int buf[MAXM], bn; char op[10001][2]; int arg[10001][3]; int main(){ int TC; scanf("%d", &TC); while (TC--){ bn = 0; int n, m; scanf("%d%d", &n, &m); N = n; for (int i = 0; i < n; ++i){ scanf("%d", arr + i); buf[bn++] = arr[i]; } for (int i = 0; i < m; ++i){ scanf("%s", op + i); if (op[i][0] == 'Q'){ scanf("%d%d%d", arg[i], arg[i] + 1, arg[i] + 2); } else{ scanf("%d%d", arg[i], arg[i] + 1); buf[bn++] = arg[i][1]; } } sort(buf, buf + bn); bn = unique(buf, buf + bn) - buf; for (int i = 0; i < bn; ++i) rec[i].clear(); for (int i = 0; i < n; ++i){ arr[i] = lower_bound(buf, buf + bn, arr[i]) - buf; rec[arr[i]].push_back(i); } for (int i = 0; i < m; ++i){ if (op[i][0] == 'Q'){ --arg[i][0]; --arg[i][1]; } else{ --arg[i][0]; arg[i][1] = lower_bound(buf, buf + bn, arg[i][1]) - buf; } } NODE1 *rt = 0; for (int i = 0; i < m; ++i){ if (op[i][0] == 'Q'){ if (i < 1) printf("%d\n", buf[query1(0, bn - 1, rt, arg[i][0], arg[i][1], arg[i][2])]); else{ printf("123\n"); } } else{ if (i < 0){ update1(0, bn - 1, rt, arg[i][0], arr[arg[i][0]], -1); update1(0, bn - 1, rt, arg[i][0], arg[i][1], 1); arr[arg[i][0]] = arg[i][1]; } } } } return 0; }