• VIJOS P1081 野生动物园 SBT、划分树模板


    【描述】

    cjBBteam拥有一个很大的野生动物园。这个动物园坐落在一个狭长的山谷内,这个区域从南到北被划分成N个区域,每个区域都饲养着一头狮子。这些狮子从北到南编号为1,2,3,…,N。每头狮子都有一个觅食能力值Ai,Ai越小觅食能力越强。饲养员cmdButtons决定对狮子进行M次投喂,每次投喂都选择一个区间[I,J],从中选取觅食能力值第K强的狮子进行投喂。值得注意的是,cmdButtons不愿意对某些区域进行过多的投喂,他认为这样有悖公平。因此cmdButtons的投喂区间是互不包含的。你的任务就是算出每次投喂后,食物被哪头狮子吃掉了。

    【输入格式】

    输入第一行有两个数N和M。此后一行有N个数,从南到北描述狮子的觅食能力值。此后M行,每行描述一次投喂。第t+2的三个数I,J,K表示在第t次投喂中,cmdButtons选择了区间[I,J]内觅食能力值第K强的狮子进行投喂。

    【输出格式】

    输出有M行,每行一个整数。第i行的整数表示在第i次投喂中吃到食物的狮子的觅食能力值。

    【样例输入】

    7 2
    1 5 2 6 3 7 4
    1 5 3
    2 7 1

    【样例输出】

    3
    2

    【分析】

    平衡树解法:

    由题目给出的区间互相不包含可以得出,若将每次询问的区间按照起始区域进行排序,那一定是一段接一段,只有可能是两种情况:

    下一段的左端与上一段的右端不相交或者相交。

    这两种情况都是前面的数据与后面的数据互不影响,因此将区间排序之后,对于每一个区间,删除掉前面多余的,插入后面不够的,使平衡树中仅留下该区间中的数据,然后直接找第k小即可。

    SBT可解。

      1 /* ***********************************************
      2 MYID    : Chen Fan
      3 LANG    : G++
      4 PROG    : VIJOS1081
      5 ************************************************ */
      6 
      7 #include <iostream>
      8 #include <cstdio>
      9 #include <cstring>
     10 #include <algorithm>
     11 
     12 using namespace std;
     13 
     14 #define MAXN 100010
     15 
     16 int sons[MAXN][2];
     17 int size[MAXN],data[MAXN];
     18 int sbt=0,sbttail=0;
     19 
     20 void rotate(int &t,int w) //rotate(&node,0/1)
     21 {
     22     int k=sons[t][1-w];
     23     if (!k) return ;
     24     sons[t][1-w]=sons[k][w];
     25     sons[k][w]=t;
     26     size[k]=size[t];
     27     size[t]=size[sons[t][0]]+size[sons[t][1]]+1;
     28     t=k;
     29 }
     30 
     31 void maintain(int& t,bool flag) //maintain(&node,flag)
     32 {
     33     if (!t) return ;
     34     if (!flag)
     35         if (size[sons[sons[t][0]][0]]>size[sons[t][1]]) rotate(t,1);
     36         else if (size[sons[sons[t][0]][1]]>size[sons[t][1]]) 
     37         {
     38             rotate(sons[t][0],0);
     39             rotate(t,1);
     40         } else return ;
     41     else
     42         if (size[sons[sons[t][1]][1]]>size[sons[t][0]]) rotate(t,0);
     43         else if (size[sons[sons[t][1]][0]]>size[sons[t][0]])
     44         {
     45             rotate(sons[t][1],1);
     46             rotate(t,0);
     47         } else return ;
     48     
     49     maintain(sons[t][0],false);
     50     maintain(sons[t][1],true);
     51     maintain(t,false);
     52     maintain(t,true);
     53 }
     54 
     55 void insert(int& t,int v) //insert(&root,0,value)
     56 {
     57     if (!t)
     58     {
     59         sbttail++;
     60         data[sbttail]=v;
     61         size[sbttail]=1;
     62         sons[sbttail][0]=0;
     63         sons[sbttail][1]=0;
     64         t=sbttail;
     65     } else 
     66     {
     67         size[t]++;
     68         if (v<data[t]) insert(sons[t][0],v);
     69         else insert(sons[t][1],v);
     70         maintain(t,v>=data[t]);
     71     }
     72 }
     73 
     74 int del(int& t,int v) //del(&root,key)
     75 {
     76     size[t]--;
     77     if (v==data[t]||(v<data[t]&&sons[t][0]==0)||(v>data[t]&&sons[t][1]==0))
     78     {
     79         int ret=data[t];
     80         if (sons[t][0]==0||sons[t][1]==0) t=sons[t][1]+sons[t][0];
     81         else data[t]=del(sons[t][0],data[t]+1);
     82         return ret;
     83     } else
     84     if (v<data[t]) return del(sons[t][0],v);
     85     else return del(sons[t][1],v);
     86 }
     87 
     88 int select(int t,int k)
     89 {
     90     if (k==size[sons[t][0]]+1) return t;
     91     if (k<=size[sons[t][0]]) return select(sons[t][0],k);
     92     else return select(sons[t][1],k-1-size[sons[t][0]]);
     93 }
     94 
     95 typedef struct nod
     96 {
     97     int i,l,r,k;
     98 } node;
     99 node d[50010];
    100 
    101 bool op(node a,node b)
    102 {
    103     if (a.l==b.l) return a.r<b.r;
    104     else return a.l<b.l;
    105 }
    106 
    107 int a[MAXN];
    108 
    109 typedef struct nod1
    110 {
    111     int i,ans;
    112 } node1;
    113 node1 out[50010];
    114 
    115 bool op1(node1 a,node1 b)
    116 {
    117     return a.i<b.i;
    118 }
    119 
    120 int main()
    121 {
    122     freopen("1.txt","r",stdin);
    123 
    124     sbt=0,sbttail=0;
    125     int n,m;
    126     scanf("%d%d",&n,&m);
    127     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    128     for (int i=1;i<=m;i++) 
    129     {
    130         scanf("%d%d%d",&d[i].l,&d[i].r,&d[i].k);
    131         d[i].i=i;
    132     }
    133     sort(&d[1],&d[m+1],op);
    134     
    135     int l=0,r=0;
    136     for (int i=1;i<=m;i++)
    137     {
    138         if (r<d[i].l)
    139         {
    140             sbt=0;
    141             sbttail=0;
    142             for (int j=d[i].l;j<=d[i].r;j++) insert(sbt,a[j]);
    143         } else 
    144         {
    145             for (int j=l;j<d[i].l;j++) del(sbt,a[j]);
    146             for (int j=r+1;j<=d[i].r;j++) insert(sbt,a[j]);
    147         }
    148         l=d[i].l;
    149         r=d[i].r;
    150         int temp=select(sbt,d[i].k);
    151         
    152         out[i].i=d[i].i;
    153         out[i].ans=data[temp];
    154     }
    155 
    156     sort(&out[1],&out[m+1],op1);
    157     for (int i=1;i<=m;i++) printf("%d
    ",out[i].ans);
    158 
    159     return 0;
    160 }
    View Code

    划分树解法:

    划分树是一种类似快排的数据结构,可以快速在O(logn)的时间内直接求出某个区间内的k值。

    然后本题就是......一棵裸的划分树,直接套即可

    。。。。。。最后的结果是,不知道为什么比SBT要慢很多,直观的感觉上划分树没有多余的删除操作,应该会快很多的

      1 /* ***********************************************
      2 MYID    : Chen Fan
      3 LANG    : G++
      4 PROG    : VIJOS1081_SortTree
      5 ************************************************ */
      6 
      7 #include <iostream>
      8 #include <cstdio>
      9 #include <cstring>
     10 #include <algorithm>
     11 
     12 using namespace std;
     13 
     14 #define MAXN 100010
     15 
     16 int a[MAXN],dp[20][MAXN],tree[20][MAXN];
     17 
     18 void maketree(int c,int l,int r)
     19 {
     20     int mid=(l+r)/2,ls=l,rs=mid+1,num=0;
     21 
     22     for (int i=mid;i>=l&&a[i]==a[mid];i--) num++;
     23     for (int i=l;i<=r;i++)
     24     {
     25         if (i==l) dp[c][i]=0;
     26         else dp[c][i]=dp[c][i-1];
     27 
     28         if (tree[c][i]<a[mid])
     29         {
     30             dp[c][i]++;
     31             tree[c+1][ls]=tree[c][i];
     32             ls++;
     33         } else 
     34         if (tree[c][i]>a[mid])
     35         {
     36             tree[c+1][rs]=tree[c][i];
     37             rs++;
     38         } else 
     39         {
     40             if (num)
     41             {
     42                 num--;
     43                 dp[c][i]++;
     44                 tree[c+1][ls]=tree[c][i];
     45                 ls++;
     46             } else 
     47             {
     48                 tree[c+1][rs]=tree[c][i];
     49                 rs++;
     50             }
     51         }
     52     }
     53 
     54     if (l==r) return ;
     55     maketree(c+1,l,mid);
     56     maketree(c+1,mid+1,r);
     57 }
     58 
     59 int query(int c,int l,int r,int ql,int qr,int k)
     60 {
     61     if (l==r) return tree[c][l];
     62     int s,ss,mid=(l+r)/2;
     63 
     64     if (l==ql)
     65     {
     66         s=0;
     67         ss=dp[c][qr];
     68     } else 
     69     {
     70         s=dp[c][ql-1];
     71         ss=dp[c][qr]-s;
     72     }
     73     if (k<=ss) return query(c+1,l,mid,l+s,l+s+ss-1,k);
     74     else return query(c+1,mid+1,r,mid-l+1+ql-s,mid-l+1+qr-s-ss,k-ss);
     75 }
     76 
     77 int main()
     78 {
     79     //freopen("1.in","r",stdin);
     80     //freopen("zoo8.in","r",stdin);
     81     //freopen("1.out","w",stdout);
     82 
     83     int n,m;
     84     scanf("%d%d",&n,&m);
     85 
     86     for (int i=1;i<=n;i++)
     87     {
     88         scanf("%d",&a[i]);
     89         tree[0][i]=a[i];
     90     }
     91     sort(&a[1],&a[n+1]);
     92 
     93     maketree(0,1,n);
     94 
     95     for (int i=1;i<=m;i++)
     96     {
     97         int l,r,k;
     98         scanf("%d%d%d",&l,&r,&k);
     99         printf("%d
    ",query(0,1,n,l,r,k));
    100     }
    101 
    102     return 0;
    103 }
    View Code
  • 相关阅读:
    P1726 上白泽慧音
    P1993 小k的农场
    P1983 车站分级
    P1525 关押罪犯【二分+二分图】
    P1268 树的重量【构造】
    P1113 杂务
    F.Three pahs on a tree
    P1522 牛的旅行
    两个约束下的dp问题
    dp 最大正方形
  • 原文地址:https://www.cnblogs.com/jcf94/p/4342068.html
Copyright © 2020-2023  润新知