• 【BZOJ1901】 Zju2112 Dynamic Rankings(树套树)


    【题意】

      给定一个含有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继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。

      对于每一个询问指令,你必须输出正确的回答。

      第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。

      分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。

       Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。

    【分析】

      带修改的区间第k大。

      如果只是询问区间的第k大的话,就是可持久化字母树。

      然后,其实我想了挺久。。。。可以看看GDXB的题解。。http://www.cnblogs.com/KonjakJuruo/p/6031832.html

      她打的是树状数组套线段树。 其实就是树状数组搞区间,然后线段树搞数值。

      因为带修改的话,是动态的。相当于不修改的时候,我们只要记录前缀和,就可以知道某段区间的和(两个前缀相减),但是修改了之后,就要用树状数组或者线段树等维护。

      这个也是这个道理,用数据结构维护区间。

      本蒟蒻打的是线段树套字母树(区间第k大,深爱字母树,耶!)

      其实树状数组套字母树应该更简单??

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 #define Maxn 10010
      9 #define Maxd 32
     10  
     11 int a[Maxn],nw[Maxn],al;
     12 char s[10];
     13  
     14 struct trie
     15 {
     16     int son[2],cnt;
     17 }tr[Maxn*30*20];int tot;
     18  
     19 void upd(int x)
     20 {
     21     tr[x].son[0]=tr[x].son[1]=0;
     22     tr[x].cnt=0;
     23 }
     24  
     25 void add(int now,int y,int c)
     26 {
     27     for(int i=Maxd;i>=1;i--)
     28     {
     29         int ind=y>>i-1;
     30         y=y%(1<<i-1);
     31         if(!tr[now].son[ind])
     32         {
     33             tr[now].son[ind]=++tot;
     34             upd(tot);
     35         }
     36         now=tr[now].son[ind];
     37         tr[now].cnt+=c;
     38     }
     39 }
     40  
     41 int query(int k)
     42 {
     43     int ans=0;
     44     for(int i=Maxd;i>=1;i--)
     45     {
     46         int ls=0;
     47         for(int j=1;j<=al;j++) ls+=tr[tr[nw[j]].son[0]].cnt;
     48         if(ls>=k)
     49         {
     50             for(int j=1;j<=al;j++) nw[j]=tr[nw[j]].son[0];       
     51         }
     52         else
     53         {
     54             k-=ls;
     55             ans+=(1<<i-1);
     56             for(int j=1;j<=al;j++) nw[j]=tr[nw[j]].son[1];
     57         }
     58     }
     59     return ans;
     60 }
     61  
     62 struct node
     63 {
     64     int l,r,lc,rc,rt;
     65 }t[Maxn*2];int len;
     66  
     67  
     68 int build(int l,int r)
     69 {
     70     int x=++len;
     71     t[x].l=l;t[x].r=r;t[x].rt=++tot;
     72     upd(tot);
     73     if(l!=r)
     74     {
     75         int mid=(l+r)>>1;
     76         t[x].lc=build(l,mid);
     77         t[x].rc=build(mid+1,r);
     78     }
     79     else t[x].lc=t[x].rc=0;
     80     return x;
     81 }
     82  
     83 void change(int x,int y,int z)
     84 {
     85     add(t[x].rt,z,1);
     86     if(a[y]!=-1) add(t[x].rt,a[y],-1);
     87     if(t[x].l==t[x].r) return;
     88     int mid=(t[x].l+t[x].r)>>1;
     89     if(y<=mid) change(t[x].lc,y,z);
     90     else change(t[x].rc,y,z);
     91 }
     92  
     93 void ffind(int x,int l,int r)
     94 {
     95     if(t[x].l==l&&t[x].r==r)
     96     {
     97         nw[++al]=t[x].rt;
     98         return;
     99     }
    100     int mid=(t[x].l+t[x].r)>>1;
    101     if(r<=mid) ffind(t[x].lc,l,r);
    102     else if(l>mid) ffind(t[x].rc,l,r);
    103     else
    104     {
    105         ffind(t[x].lc,l,mid);
    106         ffind(t[x].rc,mid+1,r);
    107     }
    108 }
    109  
    110 int n,m;
    111 void init()
    112 {
    113     len=0;tot=0;
    114     scanf("%d%d",&n,&m);
    115     build(1,n);
    116     memset(a,-1,sizeof(a));
    117     for(int i=1;i<=n;i++)
    118     {
    119         int x;
    120         scanf("%d",&x);
    121         change(1,i,x);
    122         a[i]=x;
    123     }
    124 }
    125  
    126 int main()
    127 {
    128     init();
    129     for(int i=1;i<=m;i++)
    130     {
    131         scanf("%s",s);
    132         if(s[0]=='C')
    133         {
    134             int x,y;
    135             scanf("%d%d",&x,&y);
    136             change(1,x,y);
    137             a[x]=y;
    138         }
    139         else
    140         {
    141             int x,y,k;
    142             scanf("%d%d%d",&x,&y,&k);
    143             al=0;
    144             ffind(1,x,y);
    145             printf("%d
    ",query(k));
    146         }
    147     }
    148     return 0; 
    149 }
    View Code

    2016-11-08 14:33:10

    话说树套树的离线题可以用CDQ分治??

    不会。。

  • 相关阅读:
    leetcode 150 逆波兰表达式求值
    leetcode 15 三数之和
    leetcode 12题 数字转罗马数字
    leetcode 134 加油站问题
    socket编程之多次收发数据
    socket编程
    random实现验证码功能
    ECMAScript运算符
    JavaScript数据类型
    window对象
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6042943.html
Copyright © 2020-2023  润新知