zoukankan      html  css  js  c++  java
  • [BZOJ1901]Zju2112 Dynamic Rankings

    [BZOJ1901]Zju2112 Dynamic Rankings

    试题描述

    给定一个含有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,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 

    输入

    第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。

    输出

    对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。

    输入示例

    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3

    输出示例

    3
    6

    数据规模及约定

    20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。

    题解

    线段树套线段树来一发。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <map>
    #include <set>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxval 1000000000
    #define maxn 10010
    #define maxnode 4200010
    int n;
    
    int ToT, sumv[maxnode], lc[maxnode], rc[maxnode], recs[maxnode], rcnts;
    int getsnode() {
    	if(rcnts) {
    		int o = recs[rcnts--];
    		sumv[o] = lc[o] = rc[o] = 0;
    		return o;
    	}
    	return ++ToT;
    }
    void update(int& o, int l, int r, int x, int v) {
    	if(!o) o = getsnode();
    	if(l == r) {
    		sumv[o] += v;
    		if(!sumv[o]) recs[++rcnts] = o, o = 0;
    		return ;
    	}
    	int mid = l + r >> 1;
    	if(x <= mid) update(lc[o], l, mid, x, v);
    	else update(rc[o], mid + 1, r, x, v);
    	sumv[o] = (lc[o] ? sumv[lc[o]] : 0) + (rc[o] ? sumv[rc[o]] : 0);
    	if(!sumv[o]) recs[++rcnts] = o, o = 0;
    	return ;
    }
    
    int rt[maxn<<2], No[maxn], cn;
    void modify(int L, int R, int o, int p, int x, int v) {
    	update(rt[o], 0, maxval, x, v);
    	if(L == R) return ;
    	int M = L + R >> 1, lc = o << 1, rc = lc | 1;
    	if(p <= M) modify(L, M, lc, p, x, v);
    	else modify(M+1, R, rc, p, x, v);
    	return ;
    }
    void query(int L, int R, int o, int ql, int qr) {
    	if(ql <= L && R <= qr){ No[++cn] = rt[o]; return ; }
    	int M = L + R >> 1, lc = o << 1, rc = lc | 1;
    	if(ql <= M) query(L, M, lc, ql, qr);
    	if(qr > M) query(M+1, R, rc, ql, qr);
    	return ;
    }
    
    int solve(int ql, int qr, int k) {
    	cn = 0; query(1, n, 1, ql, qr);
    	int l = 0, r = maxval;
    	while(l < r) {
    		int mid = l + r >> 1, sum = 0;
    		for(int i = 1; i <= cn; i++) if(No[i] && lc[No[i]]) sum += sumv[lc[No[i]]];
    		if(sum < k) {
    			k -= sum; l = mid + 1;
    			for(int i = 1; i <= cn; i++) if(No[i]) No[i] = rc[No[i]];
    		}
    		else {
    			r = mid;
    			for(int i = 1; i <= cn; i++) if(No[i]) No[i] = lc[No[i]];
    		}
    	}
    	return l;
    }
    
    int val[maxn];
    int main() {
    	n = read(); int q = read();
    	for(int i = 1; i <= n; i++) val[i] = read(), modify(1, n, 1, i, val[i], 1);
    	char cmd[2];
    	while(q--) {
    		scanf("%s", cmd);
    		if(cmd[0] == 'Q') {
    			int ql = read(), qr = read(), k = read();
    			printf("%d
    ", solve(ql, qr, k));
    		}
    		if(cmd[0] == 'C') {
    			int x = read(), v = read();
    			modify(1, n, 1, x, val[x], -1);
    			val[x] = v;
    			modify(1, n, 1, x, val[x], 1);
    		}
    	}
    	
    	return 0;
    }
    

    树状数组套主席树来一发。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <map>
    #include <set>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxval 1000000000
    #define maxn 10010
    #define maxnode 4200010
    int n, rt[maxn], val[maxn];
    
    int ToT, sumv[maxnode], lc[maxnode], rc[maxnode];
    void update(int& y, int x, int l, int r, int p, int v) {
    	sumv[y = ++ToT] = sumv[x] + v;
    	if(l == r) return ;
    	int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
    	if(p <= mid) update(lc[y], lc[x], l, mid, p, v);
    	else update(rc[y], rc[x], mid + 1, r, p, v);
    	return ;
    }
    
    int Rt[maxn], lrt[maxn], rrt[maxn], cl, cr;
    void modify(int p, int x, int v) {
    	for(; p <= n; p += p & -p) update(Rt[p], Rt[p], 0, maxval, x, v);
    	return ;
    }
    void query(int ql, int qr) {
    	cl = cr = 0;
    	ql--; lrt[++cl] = rt[ql];
    	for(; ql; ql -= ql & -ql) lrt[++cl] = Rt[ql];
    	rrt[++cr] = rt[qr];
    	for(; qr; qr -= qr & -qr) rrt[++cr] = Rt[qr];
    	return ;
    }
    
    int solve(int ql, int qr, int k) {
    	query(ql, qr);
    	int l = 0, r = maxval;
    	while(l < r) {
    		int mid = l + r >> 1, sum = 0;
    		for(int i = 1; i <= cr; i++) if(rrt[i] && lc[rrt[i]]) sum += sumv[lc[rrt[i]]];
    		for(int i = 1; i <= cl; i++) if(lrt[i] && lc[lrt[i]]) sum -= sumv[lc[lrt[i]]];
    		if(sum < k) {
    			k -= sum; l = mid + 1;
    			for(int i = 1; i <= cl; i++) if(lrt[i]) lrt[i] = rc[lrt[i]];
    			for(int i = 1; i <= cr; i++) if(rrt[i]) rrt[i] = rc[rrt[i]];
    		}
    		else {
    			r = mid;
    			for(int i = 1; i <= cl; i++) if(lrt[i]) lrt[i] = lc[lrt[i]];
    			for(int i = 1; i <= cr; i++) if(rrt[i]) rrt[i] = lc[rrt[i]];
    		}
    	}
    	return l;
    }
    
    int main() {
    	n = read(); int q = read();
    	for(int i = 1; i <= n; i++) {
    		val[i] = read();
    		update(rt[i], rt[i-1], 0, maxval, val[i], 1);
    	}
    	char cmd[2];
    	while(q--) {
    		scanf("%s", cmd);
    		if(cmd[0] == 'Q') {
    			int ql = read(), qr = read(), k = read();
    			printf("%d
    ", solve(ql, qr, k));
    		}
    		if(cmd[0] == 'C') {
    			int x = read(), v = read();
    			modify(x, val[x], -1);
    			modify(x, val[x] = v, 1);
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    LeetCode 623. Add One Row to Tree
    LeetCode 894. All Possible Full Binary Trees
    LeetCode 988. Smallest String Starting From Leaf
    LeetCode 979. Distribute Coins in Binary Tree
    LeetCode 814. Binary Tree Pruning
    LeetCode 951. Flip Equivalent Binary Trees
    LeetCode 426. Convert Binary Search Tree to Sorted Doubly Linked List
    LeetCode 889. Construct Binary Tree from Preorder and Postorder Traversal
    LeetCode 687. Longest Univalue Path
    LeetCode 428. Serialize and Deserialize N-ary Tree
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6349824.html
Copyright © 2011-2022 走看看