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\n",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\n",query(0,1,n,l,r,k));
100     }
101 
102     return 0;
103 }
View Code

 

 

你可能感兴趣的:(VIJOS P1081 野生动物园 SBT、划分树模板)