HYSBZ 1901 Dynamic Rankings 树状数组套主席树

ZOJ上面这题内存限制太严格,裸的树套树主席树搞法过不去,BZOJ上面这个放的比较松,可以过。

其实就是利用树状数组维护n颗主席树,然后利用前缀和性质求解第k大。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <bitset>
#include <list>
#include <cstdlib>
#include <climits>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <stack>
#include <sstream>
#include <numeric>
#include <fstream>
#include <functional>

using namespace std;

#define MP make_pair
#define PB push_back
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<int> VI;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int INF = INT_MAX / 3;
const double eps = 1e-8;
const LL LINF = 1e17;
const double DINF = 1e60;
const int maxn = 5e4 + 10;
const int maxm = maxn * 67;
const int maxq = 1e4 + 10;

struct Query {
	char cmd;
	int l, r, k;
	Query(char cmd = 0, int l = 0, int r = 0, int k = 0):
		cmd(cmd), l(l), r(r), k(k) {}
};

int sumv[maxm], lc[maxm], rc[maxm], cnt, C[maxn];
int n, m, num[maxn + maxq], numcnt, a[maxn];
Query ask[maxq];

int lowbit(int x) {
	return x & (-x);
}

void init() {
	cnt = numcnt = 0;
	memset(C, 0, sizeof(C));
}

void build(int rt, int l, int r) {
	sumv[rt] = 0;
	if(l == r) return;
	int mid = (l + r) >> 1;
	lc[rt] = cnt++; rc[rt] = cnt++;
	build(lc[rt], l, mid);
	build(rc[rt], mid + 1, r);
}

int update(int prt, int pos, int Val) {
	int nrt = cnt++, ret = nrt;
	sumv[nrt] = sumv[prt] + Val;
	int l = 0, r = numcnt - 1;
	while(l < r) {
		int mid = (l + r) >> 1;
		if(pos <= mid) {
			lc[nrt] = cnt++; rc[nrt] = rc[prt];
			sumv[lc[nrt]] = sumv[lc[prt]] + Val;
			nrt = lc[nrt]; prt = lc[prt];
			r = mid;
		}
		else {
			rc[nrt] = cnt++; lc[nrt] = lc[prt];
			sumv[rc[nrt]] = sumv[rc[prt]] + Val;
			nrt = rc[nrt]; prt = rc[prt];
			l = mid + 1;
		}
	}
	return ret;
}

void gao(int tid, int pos, int Val) {
	while(tid <= n) {
		int ret = update(C[tid], pos, Val);
		C[tid] = ret;
		tid += lowbit(tid);
	}
}

int lrt[maxn], rrt[maxn];
int query(int ql, int qr, int k) {
	int lcnt = 0, rcnt = 0;
	ql--;
	while(ql > 0) {
		lrt[lcnt++] = C[ql];
		ql -= lowbit(ql);
	}
	while(qr > 0) {
		rrt[rcnt++] = C[qr];
		qr -= lowbit(qr);
	}
	int l = 0, r = numcnt - 1;
	while(l < r) {
		int mid = (l + r) >> 1, lsum = 0, rsum = 0;
		for(int i = 0; i < lcnt; i++) lsum += sumv[lc[lrt[i]]];
		for(int i = 0; i < rcnt; i++) rsum += sumv[lc[rrt[i]]];
		if(rsum - lsum >= k) {
			r = mid;
			for(int i = 0; i < lcnt; i++) lrt[i] = lc[lrt[i]];
			for(int i = 0; i < rcnt; i++) rrt[i] = lc[rrt[i]];
		}
		else {
			l = mid + 1; k -= (rsum - lsum);
			for(int i = 0; i < lcnt; i++) lrt[i] = rc[lrt[i]];
			for(int i = 0; i < rcnt; i++) rrt[i] = rc[rrt[i]];
		}
	}
	return l;
}

int getid(int Val) {
	return lower_bound(num, num + numcnt, Val) - num;
}

int main() {
	init();
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		num[numcnt++] = a[i];
	}
	char cmd[5];
	int l, r, k;
	for(int i = 1; i <= m; i++) {
		scanf("%s", cmd);
		if(cmd[0] == ‘Q‘) {
			scanf("%d%d%d", &l, &r, &k);
			ask[i] = Query(cmd[0], l, r, k);
		}
		else {
			scanf("%d%d", &l, &k);
			ask[i] = Query(cmd[0], l, 0, k);
			num[numcnt++] = k;
		}
	}
	sort(num, num + numcnt);
	numcnt = unique(num, num + numcnt) - num;
	build(0, 0, numcnt - 1);
	for(int i = 1; i <= n; i++) {
		gao(i, getid(a[i]), 1);
	}
	for(int i = 1; i <= m; i++) {
		if(ask[i].cmd == ‘Q‘) printf("%d\n", num[query(ask[i].l, ask[i].r, ask[i].k)]);
		else {
			int prev = getid(a[ask[i].l]), now = getid(ask[i].k);
			a[ask[i].l] = ask[i].k;
			gao(ask[i].l , prev, -1); gao(ask[i].l, now, 1);
		}
	}
	return 0;
}

  

时间: 2024-12-21 22:41:23

HYSBZ 1901 Dynamic Rankings 树状数组套主席树的相关文章

【BZOJ1901】Dynamic Rankings,树状数组套主席树

Time:2016.05.09 Author:xiaoyimi 转载注明出处谢谢 传送门(权限) 题面 1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MB Submit: 6678 Solved: 2777 [Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a

关于树状数组套主席树的一些博客

哇仿佛磕了几百年啊; 废话不多说,以下是帮助很大的一些blog: ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树) 主席树全纪录(这个很好) 主席树乱讲(没啥关系,不过有些题目可以刷??) 随笔分类 - 数据结构---主席树(同上) 原文地址:https://www.cnblogs.com/wwtt/p/10099695.html

BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树

[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <string> #include <alg

[BZOJ 3196] 二逼平衡树 树状数组套主席树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3357  Solved: 1326[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为

[COGS257]动态排名系统 树状数组套主席树

257. 动态排名系统 时间限制:5 s   内存限制:512 MB [问题描述]给定一个长度为N的已知序列A[i](1<=i<=N),要求维护这个序列,能够支持以下两种操作:1.查询A[i],A[i+1],A[i+2],...,A[j](1<=i<=j<=N)中,升序排列后排名第k的数.2.修改A[i]的值为j.所谓排名第k,指一些数按照升序排列后,第k位的数.例如序列{6,1,9,6,6},排名第3的数是6,排名第5的数是9.[输入格式]第一行包含一个整数D(0<=

zoj 2112 Dynamic Rankings(树状数组套主席树)

题意:对于一段区间,每次求[l,r]的第k大,存在单点修改操作: 思路: 学习主席树参考: http://blog.csdn.net/wjf_wzzc/article/details/24560117(各种形式) http://blog.csdn.net/bossup/article/details/31921235(推荐) http://blog.csdn.net/xiaofengcanyuexj/article/details/25553521?utm_source=tuicool(图解)

【树状数组套主席树】带修改区间K大数

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

【树套树】【树状数组套主席树】

这是你顾第一次写[树套树]!!!!!!!! [原题] 求区间第k小元素,区间可修改 [正解] 如果没有修改的话,就直接写搞个主席树利用前缀和加加减减一下就好了.但是多了个修改,修改以为着从当前修改节点k到往后n-k个树顶所代表的树全部都要修改,这是一件非常操蛋的事情.回想起多年前学数据结构初步的时候,区间批量修改无非就是树状数组or线段树.故我们借用树状数组的轮廓来构建主席树的各树顶. 对树状数组每个节点,我们都当成是主席树的树顶,改树顶所涵盖的区间与树状数组该节点意义相同. [查询]查询区间[

浅谈树状数组套主席树

话说主席树还没写就先写这一篇了\(qwq\) 回顾一下主席树的实现过程:类似查分思想,将线段树的每次修改看做函数式以支持可持久化.因为这样的线段树是可减的. 那么我们维护信息的时候,就要维护每一次新形成的信息.但是我们可以根据前一个信息的基础上进行改动,而不必要去再建一棵树. 所以总而言之,是前缀和的思想. 那么,当需要修改的时候,怎么做呢? 考虑普通的区间操作,当做单点修改的时候,一般用树状数组,线段树和分块.最好实现的就是树状数组. 考虑用树状数组来维护主席树的信息. 树状数组中维护了每一次