ZOJ 2112 Dynamic Rankings

52 篇文章 0 订阅
4 篇文章 0 订阅

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 have developed a more powerful system such that for N numbers a[1], a[2], ..., a[N], you can ask it like: what is the k-th smallest number of a[i], a[i+1], ..., a[j]? (For some i<=j, 0<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.

Your task is to write a program for this computer, which

- Reads N numbers from the input (1 <= N <= 50,000)

- Processes M instructions of the input (1 <= M <= 10,000). These instructions include querying the k-th smallest number of a[i], a[i+1], ..., a[j] and change some a[i] to t.


Input

The first line of the input is a single number X (0 < X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.

The first line of each block contains two integers N and M, representing N numbers and M instruction. It is followed by N lines. The (i+1)-th line represents the number a[i]. Then M lines that is in the following format

Q i j k or
C i t

It represents to query the k-th number of a[i], a[i+1], ..., a[j] and change some a[i] to t, respectively. It is guaranteed that at any time of the operation. Any number a[i] is a non-negative integer that is less than 1,000,000,000.

There're NO breakline between two continuous test cases.


Output

For each querying operation, output one integer to represent the result. (i.e. the k-th smallest number of a[i], a[i+1],..., a[j])

There're NO breakline between two continuous test cases.


Sample Input

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


Sample Output

3
6
3

6


用静态主席树存初始的数字,然后用树状数组套线段树存之后的修改操作,可以保证不会超内存了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
const int maxn = 60505;
const int Maxn = 1000505;
const int low(int x) { return x&-x; }
int T, n, m, a[maxn], b[maxn], c[maxn], tot;
char s[2];

struct question
{
	int f, l, r, k;
}p[maxn];

struct Bit
{
	int n, m, t, tt;
	int L[Maxn], R[Maxn], sum[Maxn], frist[maxn];
	int LL[Maxn], RR[Maxn], Sum[Maxn], Frist[maxn];
	void build(int x, int y)
	{
		tt = t = n = x;		m = y;
		for (int i = 0; i <= n; i++) L[i] = R[i] = sum[i] = 0, frist[i] = i;
		for (int i = 0; i <= n; i++) LL[i] = RR[i] = Sum[i] = 0, Frist[i] = i;
	}
	void Insert(int x, int y, int z)
	{
		int bef = Frist[x - 1], now = Frist[x], l, r, mid;
		Sum[now] = Sum[bef] + z;
		for (l = 1, r = m; l < r;)
		{
			mid = (l + r) >> 1;
			if (y <= mid)
			{
				r = mid;	LL[now] = ++tt;		
				RR[now] = RR[bef];	Sum[tt] = Sum[LL[bef]] + z;
				now = LL[now];	bef = LL[bef];
			}
			else
			{
				l = mid + 1;	LL[now] = LL[bef];	
				RR[now] = ++tt; Sum[tt] = Sum[RR[bef]] + z;
				now = RR[now];	bef = RR[bef];
			}
			LL[tt] = RR[tt] = 0;
		}
	}
	void add(int x, int l, int r, int y, int z)
	{
		sum[x] += z;
		if (l == r) return;
		else
		{
			int mid = (l + r) >> 1;
			if (y <= mid)
			{
				if (!L[x]) { L[x] = ++t; L[t] = R[t] = sum[t] = 0; }
				add(L[x], l, mid, y, z);
			}
			else
			{
				if (!R[x]) { R[x] = ++t; L[t] = R[t] = sum[t] = 0; }
				add(R[x], mid + 1, r, y, z);
			}
		}
	}
	void insert(int x, int y, int z)
	{
		for (int i = x; i <= n; i += low(i)) add(frist[i], 1, m, y, z);
	}
	int query(int x, int y, int k)
	{
		int A, B, a[50], b[50];
		A = B = 0;
		for (int i = x - 1; i; i -= low(i)) a[A++] = frist[i];
		for (int i = y; i; i -= low(i)) b[B++] = frist[i];
		int l, r, result, mid, u = Frist[x - 1], v = Frist[y];
		for (l = 1, r = m; l < r;)
		{
			result = 0;		mid = (l + r) >> 1;
			for (int i = 0; i < B; i++) result += sum[L[b[i]]];
			for (int i = 0; i < A; i++) result -= sum[L[a[i]]];
			result += Sum[LL[v]] - Sum[LL[u]];
			if (k <= result)
			{
				for (int i = 0; i < B; i++) b[i] = L[b[i]];
				for (int i = 0; i < A; i++) a[i] = L[a[i]];
				u = LL[u];	v = LL[v]; r = mid;
			}
			else
			{
				for (int i = 0; i < B; i++) b[i] = R[b[i]];
				for (int i = 0; i < A; i++) a[i] = R[a[i]];
				l = mid + 1;	k -= result;	u = RR[u];	v = RR[v];
			}
		}
		return l;
	}
}bit;

int main()
{
	cin >> T;
	while (T--)
	{
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i];
		tot = n;
		for (int i = 1; i <= m; i++)
		{
			scanf("%s", s);
			if (s[0] == 'Q') p[i].f = 1, scanf("%d%d%d", &p[i].l, &p[i].r, &p[i].k);
			else
			{
				p[i].f = 0;		p[i].k = ++tot;
				scanf("%d%d", &p[i].l, &p[i].r);
				b[tot] = a[tot] = p[i].r;
			}
		}
		sort(a + 1, a + tot + 1);
		int u = unique(a + 1, a + tot + 1) - a - 1;
		bit.build(n, u);
		for (int i = 1; i <= tot; i++) c[i] = lower_bound(a + 1, a + u + 1, b[i]) - a;
		for (int i = 1; i <= n; i++) bit.Insert(i, c[i], 1);
		for (int i = 1; i <= m; i++)
		{
			if (p[i].f) printf("%d\n", a[bit.query(p[i].l, p[i].r, p[i].k)]);
			else if (c[p[i].l] != c[p[i].k])
			{
				bit.insert(p[i].l, c[p[i].l], -1);
				bit.insert(p[i].l, c[p[i].k], 1);
				c[p[i].l] = c[p[i].k];
			}
		}
	}
	return 0;
}

写了个线段树套treap的,结果炸内存了,是指针的问题吗。。。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<functional>
using namespace std;
typedef long long LL;
const int maxn = 5e4 + 10;
const int mod = 1e9 + 7;
int T, n, m, l, r, k, a[maxn];
char ch[5];

struct Node
{
	int v, p, cnt, inc;
	Node *l, *r;
	Node(int v = 0, int p = 0) :v(v), p(p){ l = r = NULL; cnt = inc = 1; }
	void clear(){ if (l) l->clear(); if (r) r->clear(); delete[]this; }
};

struct Treap
{
	#define node Node*
	#define now (*root)
	Node *root;
	void Count(node root)
	{
		root->cnt = root->inc;
		if (root->l) root->cnt += root->l->cnt;
		if (root->r) root->cnt += root->r->cnt;
	}
	void rotate_left(node *root)
	{
		node right = now->r;
		now->r = right->l;
		right->l = now;
		now = right;
		Count(now->l); Count(now);
	}
	void rotate_right(node *root)
	{
		node left = now->l;
		now->l = left->r;
		left->r = now;
		now = left;
		Count(now->r); Count(now);	
	}
	void Insert(node *root, int v, int p)
	{
		if (!now) { now = new Node(v, p); return; }
		if (now->v == v) now->inc++;
		else if (v < now->v)
		{
			Insert(&(now->l), v, p);
			if (now->l->p < now->p) rotate_right(root);
		}
		else
		{
			Insert(&(now->r), v, p);
			if (now->r->p < now->p) rotate_left(root);
		}
		Count(now);
	}
	void add(int x){ Insert(&root, x, rand() % mod); }
	void Delete(node *root, int v)
	{
		if (!now) return;
		if (v < now->v) Delete(&(now->l), v);
		if (v > now->v) Delete(&(now->r), v);
		if (v == now->v)
		{
			if (now->inc > 1) now->inc--;
			else if (!now->l || !now->r)
			{
				node temp = now;
				if (now->l) now = now->l; else now = now->r;
				delete[] temp; return;
			}
			else
			{
				if (now->l->p < now->r->p)
				{
					rotate_right(root);
					Delete(&(now->r), v);
				}
				else
				{
					rotate_left(root);
					Delete(&(now->l), v);
				}
			}
		}
		Count(now);
	}
	void dec(int x){ Delete(&root, x); }
	int find(int x)
	{
		int ans = 0;
		for (node temp = root; temp;)
		{
			int left = temp->l ? temp->l->cnt : 0;
			if (x < temp->v) temp = temp->l;
			else
			{
				if (x == temp->v) return ans + left;
				ans += left + temp->inc;
				temp = temp->r;
			}
		}
		return ans;
	}
	void clear(){ if (root) root->clear(); root=NULL; }
};

struct Tree
{
	Treap f[maxn * 4];
	void insert(int x, int l, int r)
	{
		f[x].clear();
		if (l == r) { scanf("%d", &a[l]); f[x].add(a[l]); return; }
		int mid = l + r >> 1;
		insert(x << 1, l, mid);
		insert(x << 1 | 1, mid + 1, r);
		for (int i = l; i <= r; i++) f[x].add(a[i]);
	}
	int find(int x, int l, int r, int ll, int rr, int v)
	{
		if (ll <= l&&r <= rr) return f[x].find(v);
		int mid = l + r >> 1, ans = 0;
		if (ll <= mid) ans += find(x << 1, l, mid, ll, rr, v);
		if (rr > mid) ans += find(x << 1 | 1, mid + 1, r, ll, rr, v);
		return ans;
	}
	void change(int x, int l, int r, int w, int u, int v)
	{
		f[x].dec(u);	f[x].add(v);
		if (l == r) return;
		int mid = l + r >> 1;
		if (w <= mid) change(x << 1, l, mid, w, u, v);
		else change(x << 1 | 1, mid + 1, r, w, u, v);	
	}
	void revese(int x, int l, int r)
	{
		f[x].clear();
		if (l == r) return;
		int mid = l + r >> 1;
		revese(x << 1, l, mid);
		revese(x << 1 | 1, mid + 1, r);
	}
}st;

int main()
{
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d", &n, &m);
		st.insert(1, 1, n);
		while (m--)
		{
			scanf("%s", &ch);
			if (ch[0] == 'Q')
			{
				scanf("%d%d%d", &l, &r, &k);
				int q = 0, h = 1e9;
				while (q < h)
				{
					int mid = q + h >> 1;
					int u = st.find(1, 1, n, l, r, mid);
					if (u > k - 1) h = mid - 1;
					if (u == k - 1) q = mid;
					if (u < k - 1) q = mid + 1;
					if (st.find(1, 1, n, l, r, h) == k - 1) q = h; else h--;
				}
				printf("%d\n", q);
			}
			else
			{
				scanf("%d%d", &l, &r);
				st.change(1, 1, n, l, a[l], r);a[l]=r;
			}
		}
		st.revese(1, 1, n);
	}
	return 0;
}

换了数组来写就好啦,线段树套treap

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
typedef long long LL;
int T, n, m, l, r, k;
char s[5];

struct Treaps
{
	const static int maxn = 1e6 + 3e5;
	int L[maxn], R[maxn], v[maxn], p[maxn], A[maxn], C[maxn], tot;
	void clear(){ A[0] = L[0] = R[0] = C[0] = 0; tot = 1; }
	int Node(int V, int P){ L[tot] = R[tot] = 0; v[tot] = V; p[tot] = P; A[tot] = C[tot] = 1; return tot++; }
	void Count(int x){ C[x] = A[x] + C[L[x]] + C[R[x]]; }
	void rotate_right(int &x)
	{
		int y = L[x]; L[x] = R[y]; R[y] = x; C[y] = C[x]; Count(x); x = y;
	}
	void rotate_left(int &x)
	{
		int y = R[x]; R[x] = L[y]; L[y] = x; C[y] = C[x]; Count(x); x = y;
	}
	void Insert(int& x, int V, int P)
	{
		if (!x) { x = Node(V, P); return; }
		if (v[x] == V) ++A[x];
		else if (V < v[x])
		{
			Insert(L[x], V, P);
			if (p[x]>p[L[x]]) rotate_right(x);
		}
		else
		{
			Insert(R[x], V, P);
			if (p[x] > p[R[x]]) rotate_left(x);
		}
		Count(x);
	}
	void add(int &x, int V){ Insert(x, V, rand()); }
	void Delete(int &x, int V)
	{
		if (!x) return;
		if (V < v[x]) Delete(L[x], V);
		else if (V > v[x]) Delete(R[x], V);
		else if (A[x] > 1) --A[x];
		else if (!L[x] || !R[x]) x = L[x] + R[x];
		else if (p[L[x]] < p[R[x]]){ rotate_right(x); Delete(R[x], V); }
		else { rotate_left(x); Delete(L[x], V); }
		Count(x);
	}
	void dec(int &x, int V) { Delete(x, V); }
	int find(int x, int V)
	{
		int ans = 0;
		for (int i = x; i; i = V < v[i] ? L[i] : R[i])
		{
			if (v[i] <= V) ans += C[L[i]] + A[i];
		}
		return ans;
	}
};

struct Tree
{
	const static int maxn = 2e5 + 10;
	Treaps t;
	int f[maxn], y[maxn];
	void clear(){ t.clear(); memset(f, 0, sizeof(f)); }
	void insert(int x, int l, int r)
	{
		if (l == r) { scanf("%d", &y[l]); t.add(f[x], y[l]); return; }
		int mid = l + r >> 1;
		insert(x << 1, l, mid);
		insert(x << 1 | 1, mid + 1, r);
		for (int i = l; i <= r; i++) t.add(f[x], y[i]);
	}
	int find(int x, int l, int r, int ll, int rr, int u)
	{
		if (ll <= l&&r <= rr) return t.find(f[x], u);
		int mid = l + r >> 1, ans = 0;
		if (ll <= mid) ans += find(x << 1, l, mid, ll, rr, u);
		if (rr > mid) ans += find(x << 1 | 1, mid + 1, r, ll, rr, u);
		return ans;
	}
	void change(int x, int l, int r, int u, int v)
	{
		t.dec(f[x], y[u]);	t.add(f[x], v);
		if (l == r) return;
		int mid = l + r >> 1;
		if (u <= mid) change(x << 1, l, mid, u, v);
		else change(x << 1 | 1, mid + 1, r, u, v);
	}
}solve;

int main()
{
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d", &n, &m);
		solve.clear();
		solve.insert(1, 1, n);
		while (m--)
		{
			scanf("%s", s);
			if (s[0] == 'Q')
			{
				scanf("%d%d%d", &l, &r, &k);
				int q = 0, h = 1e9;
				while (q <= h)
				{
					int mid = q + h >> 1;
					int ans = solve.find(1, 1, n, l, r, mid);
					if (ans >= k) h = mid - 1; else q = mid + 1;
				}
				printf("%d\n", q);
			}
			else
			{
				scanf("%d%d", &l, &r);
				solve.change(1, 1, n, l, r);
				solve.y[l] = r;
			}
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值