【YBTOJ】【Luogu P2617】Dynamic Rankings

链接:

洛谷

题目大意:

给定一个含有 \(n\) 个数的序列 \(a_1,a_2, \dots, a_n\),需要支持两种操作:

  • Q l r k 表示查询下标在区间 \([l,r]\) 中的第 \(k\) 小的数。
  • C x y 表示将 \(a_x\) 改为 \(y\)

正文:

和静态区间第 \(k\) 小的思路基本相同,详见 可持久化数据结构。而不同的是,因为变成动态的,原来的主席树维护的前缀和不能再这么维护了,考虑用树状数组维护那个前缀和:在跑权值线段树的时候分别开两个树状数组维护前缀和,分别表示 \([1,l-1]\) 区间和与 \([1,r]\) 区间和,显然通过这两个树状数组能得到 \([l,r]\) 前缀和。

其余操作和静态区间第 \(k\) 小就一样了,然而还有一点需要注意,这道题需要卡常,请注意你的常数问题。

代码:

const int N = 100010;

inline ll read()
{
    char c;ll f = 0, d = 1;
    while(c = getchar(), !isdigit(c)) if(c == '-') d=-1;f=(f<<3)+(f<<1)+c-48;
    while(c = getchar(), isdigit(c)) f=(f<<3)+(f<<1)+c-48;
    return d*f;
}

int n, m, nn;
ll a[N], b[N << 1]; int root[N * 600];
ll inp[N][3], t[2][N], cntl, cntr;
struct SegandTree_arrar 
{
	int lt[N * 600], rt[N * 600], cnt;
	ll sum[N * 600];
	void change(int &x, int l, int r, int p, int val)
	{
		if (!x) x = ++cnt; sum[x] += val;
		if (l == r) return;
		int mid = (l + r) >> 1;
		if(p <= mid) change(lt[x], l, mid, p, val);
		else change (rt[x], mid + 1, r, p, val);
	}
	int query(int l, int r, int k)
	{
		if (l == r) return l;
		ll ans = 0;int mid = (l + r) >> 1;
		for (int i = 1; i <= cntl; i++) ans -= sum[lt[t[0][i]]];
		for (int i = 1; i <= cntr; i++) ans += sum[lt[t[1][i]]]; 
		
		if (k <= ans)
		{
			for (int i = 1; i <= cntl; i++) t[0][i] = lt[t[0][i]];
			for (int i = 1; i <= cntr; i++) t[1][i] = lt[t[1][i]];
			return query(l, mid, k);
		}
		else
		{
			for (int i = 1; i <= cntl; i++) t[0][i] = rt[t[0][i]];
			for (int i = 1; i <= cntr; i++) t[1][i] = rt[t[1][i]];
			return query(mid + 1, r, k - ans);
		}
	 } 
	
}sgt;

void add(int pos, int val)
{
	int p = lower_bound(b + 1, b + 1 + nn, a[pos]) - b;
	for (; pos <= n; pos += pos & -pos)  
		sgt.change(root[pos], 1, nn, p, val);
}

int main()
{
	n = read(), m = read();
	for (int i = 1; i <= (nn=n); i++)
		a[i] = read(), b[i] = a[i];
	for (int i = 1; i <= m; i++)
	{
		char s[5];
		scanf ("%s", s);
		inp[i][0] = read(), inp[i][1] = read();
		if (s[0] == 'Q') inp[i][2] = read();
		else b[++nn] = inp[i][1];
	}
	sort(b + 1, b + 1 + nn);
	nn = unique(b + 1, b + 1 + nn) - b - 1;
	for (int i = 1; i <= n; i++) add(i, 1);
	for (int i = 1; i <= m; i++)
	{
		if (inp[i][2]) 
		{
			cntl = cntr = 0;
			int l = inp[i][0], r = inp[i][1];
			for (int x = r; x; x -= x & -x) t[1][++cntr] = root[x];
			for (int x = l - 1; x; x -= x & -x) t[0][++cntl] = root[x];
			printf ("%lld\n", b[sgt.query(1, nn, inp[i][2])]);
		}else
		{
			add(inp[i][0], -1);
			a[inp[i][0]] = inp[i][1];
			add(inp[i][0], 1);
		}
	}
	return 0;
} 
posted @ 2021-02-20 09:25  Jayun  阅读(44)  评论(0编辑  收藏  举报