Dynamic Rankings

传送门

这道题是带修主席树的板子题。我们先来考虑一下主席树带修改最暴力的做法,就是暴力修改与之有关的所有权值线段树,这样的话单次操作的复杂度就是\(O(nlogn)\)的,总体的操作就是\(O(n^2logn)\)的,显然吃不消。

因为主席树其实应用的是前缀和的思想,我们考虑一下在最开始的时候,我们是怎么维护单点修改的前缀和的?使用树状数组。在普通的主席树里我们用的是差分的思想,但是现在我们不用差分了,我们用树状数组的思想(有人说叫套一个树状数组,但是其实我觉得没有实际套上……怎么说都行),使得根节点为\(root_x\)的主席树维护的是\(lowbit_x\)区间之内的权值,修改的时候像树状数组一样修改,查询的时候也一样查询,之后就和普通的主席树很相似了。

在实现上还是有很多细节的。修改和建树不难,因为这时不需要考虑继承上一个根结点的信息,直接修改就可以。不过在查询的时候,我们不能先进入树中之后再调用\(lowbit\)进行循环查询,因为进入树中之后我们就不知道下一步往哪走了。所以解决办法是一开始先把\(l-1\)和\(r\)能访问到的区间都跑出来,把他们的根节点存在数组里,之后在询问的时候,同步的把所有根节点都向其左/右儿子移动就可以了,顺便使用这个来统计答案,确定应该往哪边走。

这样的话这道题修改是\(O(log^2n)\),总复杂度为\(O(nlog^2n)\),可以通过。

还有就是此题实际上不需要离散化,因为主席树上权值只是用来帮你判断应该往哪走,这题因为没要求强制在线,所以可以像我一样,先离线把所有的都存下来,之后进行离散化之后再操作,也可以不离散直接操作,但是这样二分的边界会大一点。

我自己试了一下,对于普通的主席树,其实离不离散对于答案的正确性影响不大,但是如果不离散,那么二分的范围必须开到上下界,也就是稳定的\(O(nlogmax_{val})\),但是离散化以后就会好很多。不离散的话会浪费时间和空间,不过其实也不会太多,一般会多几个常数的\(O(n)\)复杂度,差的不是很多。比如这题离不离散只差了1000ms(一共14000ms)。

所以离不离散的话可能ssy说的对:“你觉得不离散过不去的时候。”

看一下代码。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar(‘\n‘)
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
#define lowbit(x) x & (-x)
using namespace std;
typedef long long ll;
const int M = 400005;
const int N = 30000005;

int read()
{
   int ans = 0,op = 1;
   char ch = getchar();
   while(ch < ‘0‘ || ch > ‘9‘)
   {
      if(ch == ‘-‘) op = -1;
      ch = getchar();
   }
   while(ch >=‘0‘ && ch <= ‘9‘)
   {
      ans *= 10;
      ans += ch - ‘0‘;
      ch = getchar();
   }
   return ans * op;
}

struct node
{
   int ls,rs,v;
}t[N];

int a[M],b[M],n,m,x[M],y[M],z[M],c[M],idx,t1[M],t2[M],cnt1,cnt2,root[M],tot;
char s[2];

void modify(int &p,int l,int r,int pos,int val)
{
   if(!p) p = ++idx;
   t[p].v += val;
   if(l == r) return;
   int mid = (l+r) >> 1;
   if(pos <= mid) modify(t[p].ls,l,mid,pos,val);
   else modify(t[p].rs,mid+1,r,pos,val);
}

void change(int pos,int val)
{
   int x = pos;
   while(x <= n) modify(root[x],1,tot,a[pos],-1),x += lowbit(x);
   a[pos] = val,x = pos;
   while(x <= n) modify(root[x],1,tot,a[pos],1),x += lowbit(x);
}

int query(int l,int r,int k)
{
   if(l == r) return l;
   int sum = 0,mid = (l+r) >> 1;
   rep(i,1,cnt1) sum -= t[t[t1[i]].ls].v;
   rep(i,1,cnt2) sum += t[t[t2[i]].ls].v;
   if(k <= sum)
   {
      rep(i,1,cnt1) t1[i] = t[t1[i]].ls;
      rep(i,1,cnt2) t2[i] = t[t2[i]].ls;
      return query(l,mid,k);
   }
   else
   {
      rep(i,1,cnt1) t1[i] = t[t1[i]].rs;
      rep(i,1,cnt2) t2[i] = t[t2[i]].rs;
      return query(mid+1,r,k - sum);
   }
}

int main()
{
   n = read(),m = read();
   rep(i,1,n) a[i] = b[i] = read();
   rep(i,1,m)
   {
      scanf("%s",s);
      if(s[0] == ‘Q‘) x[i] = read(),y[i] = read(),z[i] = read();
      else c[i] = read(),a[i+n] = b[i+n] = read();
   }
   sort(b+1,b+n+m+1);
   tot = unique(b+1,b+1+n+m) - b - 1;
   rep(i,1,n+m) a[i] = lower_bound(b+1,b+1+tot,a[i]) - b;
   rep(i,1,n)
   {
      int j = i;
      while(j <= n) modify(root[j],1,tot,a[i],1),j += lowbit(j);
   }
   rep(i,1,m)
   {
      if(!x[i]) {change(c[i],a[i+n]);continue;}
      int j = x[i] - 1,k = y[i];
      cnt1 = cnt2 = 0;
      while(j) t1[++cnt1] = root[j],j -= lowbit(j);
      while(k) t2[++cnt2] = root[k],k -= lowbit(k);
      printf("%d\n",b[query(1,tot,z[i])]);
   }
   return 0;
}

原文地址:https://www.cnblogs.com/captain1/p/10099826.html

时间: 2024-10-09 07:01:27

Dynamic Rankings的相关文章

BZOJ 1901 Dynamic Rankings

题面: 1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 8088  Solved: 3364[Submit][Status][Discuss] Description 给定一个含有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),并且,你可以改变

1901: Zju2112 Dynamic Rankings

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5268  Solved: 2207[Submit][Status][Discuss] Description 给定一个含有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

【BZOJ-1901】Dynamic Rankings 带修主席树

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7292  Solved: 3038[Submit][Status][Discuss] Description 给定一个含有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

[bzoj1901][zoj2112][Dynamic Rankings]

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB 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

ZOJ 2112 Dynamic Rankings(主席树の动态kth)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 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. T

【BZOJ1901】Dynamic Rankings [整体二分]

Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 给定一个含有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继续回答上面的问题.你需要编一个这样的程序

zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap

Dynamic Rankings Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 Description The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query l

bzoj 1901: Zju2112 Dynamic Rankings(树套树)

1901: Zju2112 Dynamic Rankings 经典的带修改求区间第k小值问题 树套树模板,我是用的线段树套splay实现的,而且用的数组模拟的,所以可能空间略大,bzoj过了,zoj过不了. 思路很简单,用线段树维护区间,用splay维护区间内的权值,然后询问的时候,二分答案key,然后在区间内找小于key的数有多少个. 贴上模板: #include<stdio.h> #include<string.h> #include<algorithm> #def

ZOJ 2112 Dynamic Rankings(带修改的区间第K大,分块+二分搜索+二分答案)

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB 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

BZOJ 1901: Zju2112 Dynamic Rankings 区间k大 带修改 在线 线段树套平衡树

之前写线段树套splay数组版..写了6.2k..然后弃疗了.现在发现还是很水的..嘎嘎.. zju过不了,超时. upd:才发现zju是多组数据..TLE一版才发现.然后改了,MLE...手写内存池..尼玛终于过了..附zju2112代码于后. bzoj倒是过了,1A的感觉还是很爽的..可是时间不好看..这就是所谓\(O(nlog^3n)\)的复杂度的可怜之处么? 写挂的地方: insert一定要是传地址指针进去. delete时先把地址指针delete掉,最后把是地址指针指向左儿子or右儿子