zoukankan      html  css  js  c++  java
  • 【POJ2104】K-th Number(主席树)

    题意:有n个数组成的序列,要求维护数据结构支持在线的下列两种操作:

    1:单点修改,将第x个数修改成y

    2:区间查询,询问从第x个数到第y个之间第K大的数

    n<=100000,a[i]<=10^9

    思路:一年前写过的第一道主席树,现在有了更深的理解

    最朴素的想法是设t[i,j]为i时刻[1..j]的个数之和

    询问时区间(x,y)时只需取出t[y]-t[x-1]这棵线段树,在其中二分查找即可

    那么问题来了:这样的写法空间复杂度是O(n2)级别的,且每次更改只有logn个点会被更改

    有很多一模一样的线段树中的节点是重复的,如何利用它们

    充分利用历史版本,使用类似链表的方法将它们链接

    比如只有左儿子被修改的节点就只新开左儿子,右儿子链到上一个时刻的右儿子即可

    单点修改的时间和空间复杂度都是O(NlogN)

     1 var t:array[0..2000000]of record
     2                            l,r,s:longint;
     3                           end;
     4     a,b,c,d,root:array[0..210000]of longint;
     5     n,m,i,x,y,k,cnt:longint;
     6 
     7 procedure swap(var x,y:longint);
     8 var t:longint;
     9 begin
    10  t:=x; x:=y; y:=t;
    11 end;
    12 
    13 procedure qsort(l,r:longint);
    14 var i,j,mid:longint;
    15 begin
    16  i:=l; j:=r; mid:=a[(l+r)>>1];
    17  repeat
    18   while mid>a[i] do inc(i);
    19   while mid<a[j] do dec(j);
    20   if i<=j then
    21   begin
    22    swap(a[i],a[j]);
    23    swap(c[i],c[j]);
    24    inc(i); dec(j);
    25   end;
    26  until i>j;
    27  if l<j then qsort(l,j);
    28  if i<r then qsort(i,r);
    29 end;
    30 
    31 procedure update(l,r:longint;var p:longint;x:longint);
    32 var mid:longint;
    33 begin
    34  inc(cnt);
    35  t[cnt]:=t[p];
    36  p:=cnt;
    37  inc(t[p].s);
    38  if l=r then exit;
    39  mid:=(l+r)>>1;
    40  if x<=mid then update(l,mid,t[p].l,x)
    41   else update(mid+1,r,t[p].r,x);
    42 end;
    43 
    44 function query(p1,p2,l,r,k:longint):longint;
    45 var mid,tmp:longint;
    46 begin
    47  if l=r then exit(l);
    48  tmp:=t[t[p2].l].s-t[t[p1].l].s;
    49  mid:=(l+r)>>1;
    50  if tmp>=k then exit(query(t[p1].l,t[p2].l,l,mid,k))
    51   else exit(query(t[p1].r,t[p2].r,mid+1,r,k-tmp));
    52 end;
    53 
    54 begin
    55  assign(input,'poj2104.in'); reset(input);
    56  assign(output,'poj2104.out'); rewrite(output);
    57  readln(n,m);
    58  for i:=1 to n do
    59  begin
    60   read(a[i]); b[i]:=a[i]; c[i]:=i;
    61  end;
    62  qsort(1,n);
    63  d[c[1]]:=1;
    64  for i:=2 to n do
    65   if a[i]<>a[i-1] then d[c[i]]:=d[c[i-1]]+1
    66    else d[c[i]]:=d[c[i-1]];
    67  for i:=1 to n do
    68  begin
    69   root[i]:=root[i-1];
    70   update(1,n,root[i],d[i]);
    71  end;
    72  for i:=1 to m do
    73  begin
    74   readln(x,y,k);
    75   writeln(a[query(root[x-1],root[y],1,n,k)]);
    76  end;
    77  close(input);
    78  close(output);
    79 end.

     UPD(2018.9.19):C++

      1 //无修改区间第K小值
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<string>
      5 #include<cmath>
      6 #include<iostream>
      7 #include<algorithm>
      8 #include<map>
      9 #include<set>
     10 #include<queue>
     11 #include<vector>
     12 using namespace std;
     13 typedef long long ll;
     14 typedef unsigned int uint;
     15 typedef unsigned long long ull;
     16 typedef pair<int,int> PII;
     17 typedef vector<int> VI;
     18 #define fi first
     19 #define se second 
     20 #define MP make_pair
     21 #define N   210000
     22 #define MOD 1000000007
     23 #define eps 1e-8 
     24 #define pi acos(-1)
     25 #define oo 1e9
     26 
     27 struct arr
     28 {
     29     int l,r,s;
     30 }t[2100000];
     31 int a[N],b[N],c[N],root[N],cnt,n;
     32 
     33 
     34 int read()
     35 { 
     36    int v=0,f=1;
     37    char c=getchar();
     38    while(c<48||57<c) {if(c=='-') f=-1; c=getchar();}
     39    while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
     40    return v*f;
     41 }
     42 
     43 int Discrete(int x)
     44 {
     45     int l=1;
     46     int r=n;
     47     while(l<=r)
     48     {
     49         int mid=(l+r)>>1;
     50         if(b[mid]==x) return c[mid];
     51         if(b[mid]<x) l=mid+1;
     52          else r=mid-1;
     53     }
     54 }
     55 
     56 void update(int l,int r,int x,int &p)
     57 {
     58     t[++cnt].l=t[p].l;
     59     t[cnt].r=t[p].r;
     60     t[cnt].s=t[p].s;
     61     p=cnt;
     62     t[p].s++;
     63     if(l==r) return;
     64     int mid=(l+r)>>1;
     65     if(x<=mid) update(l,mid,x,t[p].l);
     66      else update(mid+1,r,x,t[p].r);
     67 } 
     68     
     69 int query(int p1,int p2,int l,int r,int k)
     70 {
     71     if(l==r) return l;
     72     int tmp=t[t[p2].l].s-t[t[p1].l].s;
     73     int mid=(l+r)>>1;
     74     if(tmp>=k) return query(t[p1].l,t[p2].l,l,mid,k); 
     75      else return query(t[p1].r,t[p2].r,mid+1,r,k-tmp);
     76 }
     77 
     78 int main()
     79 {
     80     //freopen("poj2104.in","r",stdin);
     81     //freopen("poj2104.out","w",stdout);
     82     int m;
     83     scanf("%d%d",&n,&m);
     84     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
     85     for(int i=1;i<=n;i++) b[i]=a[i];
     86     sort(b+1,b+n+1);
     87     c[1]=1;
     88     for(int i=2;i<=n;i++)
     89     {
     90         c[i]=c[i-1];
     91         if(b[i]!=b[i-1]) c[i]++;
     92     }        
     93     for(int i=1;i<=n;i++) a[i]=Discrete(a[i]); //离散化
     94     for(int i=1;i<=n;i++)
     95     {
     96         root[i]=root[i-1];
     97         update(1,n,a[i],root[i]);
     98     }
     99     for(int i=1;i<=m;i++)
    100     {
    101         int x,y,k;
    102         scanf("%d%d%d",&x,&y,&k);
    103         int ans=b[query(root[x-1],root[y],1,n,k)];
    104         printf("%d
    ",ans);
    105     }
    106     
    107     return 0;
    108 }
    109 
    110             
    111         
  • 相关阅读:
    编写一个程序,获取10个1至20的随机数,要求随机数不能重复。并把最终的随机数输出到控制台。
    代码实现集合嵌套之ArrayList嵌套ArrayList
    代码实现模拟进栈出栈
    代码实现:键盘录入任意一个年份,判断该年是闰年还是平年
    代码实现你来到这个世界多少天?
    代码实现:以下一个字符串:”91 27 46 38 50”,请写代码实现最终输出结果是:”27 38 46 50 91”
    代码实现把字符串反转
    编写代码实现把一个字符串的首字母转成大写,其余为小写。
    编写代码实现:统计一个字符串中大写字母字符,小写字母字符,数字字符出现的次数,其他字符出现的次数
    编写代码实现模拟登录,给三次机会,并提示还有几次
  • 原文地址:https://www.cnblogs.com/myx12345/p/6131016.html
Copyright © 2011-2022 走看看