【Tyvj1601】魔兽争霸(主席树,树套树)

题意:要求在N个数的序列中支持以下操作:

1:将第X个元素加上Y

2:询问当前K大值

n<=30000,m<=50000

思路:树状数组套主席树

Tyvj又炸了,还不知道对不对

  1 var t:array[0..12000000]of record
  2                            l,r,s:longint;
  3                           end;
  4     d:array[1..50000,1..3]of longint;
  5     a,save,q,root,hash:array[0..100000]of longint;
  6     b:array[1..200000]of longint;
  7     n,m,i,j,x,cnt,u,que,s,sum,tmp,len:longint;
  8     ch:string;
  9
 10 function lowbit(x:longint):longint;
 11 begin
 12  exit(x and (-x));
 13 end;
 14
 15 procedure update(l,r:longint;var p:longint;x,v:longint);
 16 var mid:longint;
 17 begin
 18  inc(cnt); t[cnt]:=t[p];
 19  p:=cnt; t[p].s:=t[p].s+v;
 20  if l=r then exit;
 21  mid:=(l+r)>>1;
 22  if x<=mid then update(l,mid,t[p].l,x,v)
 23   else update(mid+1,r,t[p].r,x,v);
 24 end;
 25
 26 function query(l,r,k:longint):longint;
 27 var mid,s,i:longint;
 28 begin
 29  if l=r then exit(l);
 30  s:=0;
 31  mid:=(l+r)>>1;
 32  for i:=1 to len do s:=s+t[t[q[i]].l].s;
 33  if s>=k then
 34  begin
 35   for i:=1 to len do q[i]:=t[q[i]].l;
 36   exit(query(l,mid,k));
 37  end
 38   else
 39   begin
 40    for i:=1 to len do q[i]:=t[q[i]].r;
 41    exit(query(mid+1,r,k-s));
 42   end;
 43 end;
 44
 45 procedure swap(var x,y:longint);
 46 var t:longint;
 47 begin
 48  t:=x; x:=y; y:=t;
 49 end;
 50
 51 procedure qsort(l,r:longint);
 52 var i,j,mid:longint;
 53 begin
 54  i:=l; j:=r; mid:=b[(l+r)>>1];
 55  repeat
 56   while mid<b[i] do inc(i);
 57   while mid>b[j] do dec(j);
 58   if i<=j then
 59   begin
 60    swap(b[i],b[j]);
 61    inc(i); dec(j);
 62   end;
 63  until i>j;
 64  if l<j then qsort(l,j);
 65  if i<r then qsort(i,r);
 66 end;
 67
 68 function find(x:longint):longint;
 69 var l,r,mid:longint;
 70 begin
 71  l:=1; r:=u;
 72  while l<=r do
 73  begin
 74   mid:=(l+r)>>1;
 75   if hash[mid]=x then exit(mid);
 76   if hash[mid]>x then l:=mid+1
 77    else r:=mid-1;
 78  end;
 79 end;
 80
 81 begin
 82  assign(input,‘tyvj1601.in‘); reset(input);
 83  assign(output,‘tyvj1601.out‘); rewrite(output);
 84  readln(n);
 85  for i:=1 to n do
 86  begin
 87   read(a[i]); b[i]:=a[i];
 88  end;
 89  que:=n;
 90  for i:=1 to n do save[i]:=a[i];
 91  readln(m);
 92  for i:=1 to m do
 93  begin
 94   readln(ch); x:=0;
 95   if ch[1]=‘Q‘ then
 96   begin
 97    for j:=3 to length(ch) do x:=x*10+ord(ch[j])-ord(‘0‘);
 98    d[i,1]:=1; d[i,2]:=x; continue;
 99   end;
100   d[i,1]:=2; s:=2;
101   for j:=3 to length(ch) do
102   begin
103    if ch[j]=‘ ‘ then inc(s)
104     else d[i,s]:=d[i,s]*10+ord(ch[j])-ord(‘0‘);
105   end;
106   if ch[1]=‘A‘ then d[i,3]:=-d[i,3];
107  end;
108  for i:=1 to m do
109   if d[i,1]=2 then
110   begin
111    a[d[i,2]]:=a[d[i,2]]+d[i,3];
112    if a[d[i,2]]>0 then
113    begin
114     inc(que); b[que]:=a[d[i,2]];
115    end;
116   end;
117  qsort(1,que);
118  hash[1]:=b[1]; u:=1;
119  for i:=2 to que do
120   if b[i]<>b[i-1] then begin inc(u); hash[u]:=b[i]; end;
121  sum:=n;
122  for i:=1 to n do
123  begin
124   tmp:=find(save[i]);
125   j:=i;
126   while j<=n do
127   begin
128    update(1,u,root[j],tmp,1);
129    j:=j+lowbit(j);
130   end;
131  end;
132  for i:=1 to m do
133   if d[i,1]=1 then
134   begin
135    len:=0; j:=n;
136    while j>0 do
137    begin
138     inc(len); q[len]:=root[j];
139     j:=j-lowbit(j);
140    end;
141    if sum<d[i,2] then writeln(-1)
142     else writeln(hash[query(1,u,d[i,2])]);
143   end
144    else
145    begin
146     tmp:=find(save[d[i,2]]);
147     j:=d[i,2];
148     while j<=n do
149     begin
150      update(1,u,root[j],tmp,-1);
151      j:=j+lowbit(j);
152     end;
153     save[d[i,2]]:=save[d[i,2]]+d[i,3];
154     if save[d[i,2]]>0 then
155     begin
156      tmp:=find(save[d[i,2]]);
157      j:=d[i,2];
158      while j<=n do
159      begin
160       update(1,u,root[j],tmp,1);
161       j:=j+lowbit(j);
162      end;
163     end
164      else dec(sum);
165    end;
166
167  writeln(sum);
168  close(input);
169  close(output);
170 end.
时间: 2024-10-15 11:13:33

【Tyvj1601】魔兽争霸(主席树,树套树)的相关文章

ZOJ 2112 Dynamic Rankings(主席树套树状数组+静态主席树)

题意:给定一个区间,求这个区间第k大的数,支持单点修改. 思路:主席树真是个神奇的东西.........速度很快但是也有一个问题就是占用内存的很大,一般来说支持单点修改的主席树套树状数组空间复杂度为O(n*logn*logn), 如果查询较少的话,可以初始的时候用一颗静态主席树,这样空间复杂度可以降为O(n*logn+q*logn*logn),勉强可以过zoj这道题. 这道题看了好久好久才懂...网上题解一般就几句话.......下面是自己的一些理解. 首先静态主席树这个东西其实比较好懂,就是对

Dynamic Ranking(主席树,树套树,树状数组)

洛谷题目传送门 YCB巨佬对此题有详细的讲解.%YCB%请点这里 思路分析 不能套用静态主席树的方法了.因为的\(N\)个线段树相互纠缠,一旦改了一个点,整个主席树统统都要改一遍...... 话说我真的快要忘了有一种数据结构,能支持单点修改,区间查询,更重要的是,常数优秀的它专门用来高效维护前缀和!!它就是-- !树状数组! 之前静态主席树要保存的每个线段树\([1,i]\),不也是一个庞大的前缀吗?于是,把树状数组套在线段树上,构成支持动态修改的主席树.每个树状数组的节点即为一个线段树的根节点

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

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

BZOJ3295 动态逆序对 树套树, 树状数组套线段树(主席树)

Orz黄学长,蒟蒻在黄学长的带领下,通过阅读黄学长的代码!终于会了这道题! 首先我想先说一下这道题的思路(准确来说是黄学长的). 很明显,树状数组应该不用讲吧!关键是内存怎么开,维护一些什么样的数据? 其实我们通过观察,很快可以发现,你维护被删的数比维护所有的数轻松多了(不管是空间上,还是时间上).所以我们就可以从这方面想!(其实我一开始的思路,因为这道题我已经看过很久了,一直想写,毕竟是白书里面的一道例题嘛!一开始,蒟蒻的我是打算这样的用树状数组套权值线段树,并且是维护所有的数,我发现空间不够

树套树三题 题解

1.COGS 1534 [NEERC 2004]K小数 其实是主席树裸题…… (其实这题数据非常水……从O(nlogn)的主席树到O(nlog3n)的树套树+二分到O(nsqrt(n)log2n)的分块套二分套二分到O(n2)的暴力都能过……) 鉴于这就是动态排名系统的静态版,就不说了,贴代码: 线段树套平衡树: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; con

BZOJ 3196 二逼平衡树 树套树

题目大意:...BZOJ挂了自己看去 好吧既然BZOJ挂了我还是贴上来吧0.0 破服务器 维护一种数据结构,提供下列操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) 其实一开始觉得这题是划分树主席树之类的 然后去了解了一下发现完全写不了... 后来才知道原来是树套树 以前想过线段树套树状数组 这数据范围别说树套树了连树状数组都开不开 正解应该是

主席树/函数式线段树/可持久化线段树

什么是主席树 可持久化数据结构(Persistent data structure)就是利用函数式编程的思想使其支持询问历史版本.同时充分利用它们之间的共同数据来减少时间和空间消耗. 因此可持久化线段树也叫函数式线段树又叫主席树. 可持久化数据结构 在算法执行的过程中,会发现在更新一个动态集合时,需要维护其过去的版本.这样的集合称为是可持久的. 实现持久集合的一种方法时每当该集合被修改时,就将其整个的复制下来,但是这种方法会降低执行速度并占用过多的空间. 考虑一个持久集合S. 如图所示,对集合的

树套树Day2

滚回来更新,,, 在Day1我们学了最基本的线段树套平衡树 Day2开始我们要学习一些黑科技 (所以很大概率会出现Day3 w 1.线段树上的黑科技 这一段我们分几项来讲 1.权值线段树 权值线段树以权值为下标建树(就像求逆序对时用的树状数组),一开始所有节点都为0,通过线段树的区间极值,区间和来表示"这个区间上有多少个数"等信息. 下面这个代码并没有离散化因为我懒得写↓ #include <iostream> #include <cstdio> using n

树套树乱讲

树套树乱讲 树状数组套线段树 先学会主席树. 主席树可以被理解为一个二维平面,其中n棵树可以视作横轴,每棵树中的坐标范围(也就是线段树的坐标范围)可以视作纵轴.这样一来就是用主席树维护了一些在二维平面上的点,给定\(a,b,c,d\),可以在\(O(\log{n})\)的时间内求出满足\(a\le x_i\le b,c\le y_i\le d\)的\(i\)的数量. 而树状数组套线段树就是把这个问题动态化. 对于上述的问题,我们是通过对主席树直接维护前缀和,查询时两棵主席树相减,再在区间\([c

知识点 - 线段树 权值 树套树 二维 可持续

知识点 - 线段树 权值 树套树 二维 可持续 //区间更新求和 inline int ls(int p) { return p << 1; }//左儿子 inline int rs(int p) { return p << 1 | 1; }//右儿子 void push_up(int p) { t[p] = t[ls(p)] + t[rs(p)]; }// 向上不断维护区间操作 void build(ll p, ll l, ll r) { if (l == r) { t[p] =