【描述】

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次投喂中吃到食物的狮子的觅食能力值。

【样例输入】


【样例输出】


【分析】

平衡树解法:

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

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

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

SBT可解。

 /* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : VIJOS1081
************************************************ */ #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std; #define MAXN 100010 int sons[MAXN][];
int size[MAXN],data[MAXN];
int sbt=,sbttail=; void rotate(int &t,int w) //rotate(&node,0/1)
{
int k=sons[t][-w];
if (!k) return ;
sons[t][-w]=sons[k][w];
sons[k][w]=t;
size[k]=size[t];
size[t]=size[sons[t][]]+size[sons[t][]]+;
t=k;
} void maintain(int& t,bool flag) //maintain(&node,flag)
{
if (!t) return ;
if (!flag)
if (size[sons[sons[t][]][]]>size[sons[t][]]) rotate(t,);
else if (size[sons[sons[t][]][]]>size[sons[t][]])
{
rotate(sons[t][],);
rotate(t,);
} else return ;
else
if (size[sons[sons[t][]][]]>size[sons[t][]]) rotate(t,);
else if (size[sons[sons[t][]][]]>size[sons[t][]])
{
rotate(sons[t][],);
rotate(t,);
} else return ; maintain(sons[t][],false);
maintain(sons[t][],true);
maintain(t,false);
maintain(t,true);
} void insert(int& t,int v) //insert(&root,0,value)
{
if (!t)
{
sbttail++;
data[sbttail]=v;
size[sbttail]=;
sons[sbttail][]=;
sons[sbttail][]=;
t=sbttail;
} else
{
size[t]++;
if (v<data[t]) insert(sons[t][],v);
else insert(sons[t][],v);
maintain(t,v>=data[t]);
}
} int del(int& t,int v) //del(&root,key)
{
size[t]--;
if (v==data[t]||(v<data[t]&&sons[t][]==)||(v>data[t]&&sons[t][]==))
{
int ret=data[t];
if (sons[t][]==||sons[t][]==) t=sons[t][]+sons[t][];
else data[t]=del(sons[t][],data[t]+);
return ret;
} else
if (v<data[t]) return del(sons[t][],v);
else return del(sons[t][],v);
} int select(int t,int k)
{
if (k==size[sons[t][]]+) return t;
if (k<=size[sons[t][]]) return select(sons[t][],k);
else return select(sons[t][],k--size[sons[t][]]);
} typedef struct nod
{
int i,l,r,k;
} node;
node d[]; bool op(node a,node b)
{
if (a.l==b.l) return a.r<b.r;
else return a.l<b.l;
} int a[MAXN]; typedef struct nod1
{
int i,ans;
} node1;
node1 out[]; bool op1(node1 a,node1 b)
{
return a.i<b.i;
} int main()
{
freopen("1.txt","r",stdin); sbt=,sbttail=;
int n,m;
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++) scanf("%d",&a[i]);
for (int i=;i<=m;i++)
{
scanf("%d%d%d",&d[i].l,&d[i].r,&d[i].k);
d[i].i=i;
}
sort(&d[],&d[m+],op); int l=,r=;
for (int i=;i<=m;i++)
{
if (r<d[i].l)
{
sbt=;
sbttail=;
for (int j=d[i].l;j<=d[i].r;j++) insert(sbt,a[j]);
} else
{
for (int j=l;j<d[i].l;j++) del(sbt,a[j]);
for (int j=r+;j<=d[i].r;j++) insert(sbt,a[j]);
}
l=d[i].l;
r=d[i].r;
int temp=select(sbt,d[i].k); out[i].i=d[i].i;
out[i].ans=data[temp];
} sort(&out[],&out[m+],op1);
for (int i=;i<=m;i++) printf("%d\n",out[i].ans); return ;
}

划分树解法:

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

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

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

 /* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : VIJOS1081_SortTree
************************************************ */ #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std; #define MAXN 100010 int a[MAXN],dp[][MAXN],tree[][MAXN]; void maketree(int c,int l,int r)
{
int mid=(l+r)/,ls=l,rs=mid+,num=; for (int i=mid;i>=l&&a[i]==a[mid];i--) num++;
for (int i=l;i<=r;i++)
{
if (i==l) dp[c][i]=;
else dp[c][i]=dp[c][i-]; if (tree[c][i]<a[mid])
{
dp[c][i]++;
tree[c+][ls]=tree[c][i];
ls++;
} else
if (tree[c][i]>a[mid])
{
tree[c+][rs]=tree[c][i];
rs++;
} else
{
if (num)
{
num--;
dp[c][i]++;
tree[c+][ls]=tree[c][i];
ls++;
} else
{
tree[c+][rs]=tree[c][i];
rs++;
}
}
} if (l==r) return ;
maketree(c+,l,mid);
maketree(c+,mid+,r);
} int query(int c,int l,int r,int ql,int qr,int k)
{
if (l==r) return tree[c][l];
int s,ss,mid=(l+r)/; if (l==ql)
{
s=;
ss=dp[c][qr];
} else
{
s=dp[c][ql-];
ss=dp[c][qr]-s;
}
if (k<=ss) return query(c+,l,mid,l+s,l+s+ss-,k);
else return query(c+,mid+,r,mid-l++ql-s,mid-l++qr-s-ss,k-ss);
} int main()
{
//freopen("1.in","r",stdin);
//freopen("zoo8.in","r",stdin);
//freopen("1.out","w",stdout); int n,m;
scanf("%d%d",&n,&m); for (int i=;i<=n;i++)
{
scanf("%d",&a[i]);
tree[][i]=a[i];
}
sort(&a[],&a[n+]); maketree(,,n); for (int i=;i<=m;i++)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",query(,,n,l,r,k));
} return ;
}

VIJOS P1081 野生动物园 SBT、划分树模板的更多相关文章

  1. vijos 1081 野生动物园 函数式线段树

    描述 cjBBteam拥有一个很大的野生动物园.这个动物园坐落在一个狭长的山谷内,这个区域从南到北被划分成N个区域,每个区域都饲养着一头狮子.这些狮子从北到南编号为1,2,3,…,N.每头狮子都有一个 ...

  2. hdu 2665 Kth number(划分树模板)

    http://acm.hdu.edu.cn/showproblem.php?pid=2665 [ poj 2104 2761 ]  改变一下输入就可以过 http://poj.org/problem? ...

  3. poj2104(划分树模板)

    poj2104 题意 给出一个序列,每次查询一个区间,要求告诉这个区间排序后的第k个数. 分析 划分树模板,O(mlogn). 建树.根据排序之后的数组,对于一个区间,找到中点的数,将整个区间分为左右 ...

  4. poj2104(划分树模板)

    poj2104 题意 给出一个序列,每次查询一个区间,要求告诉这个区间排序后的第k个数. 分析 划分树模板,O(mlogn). 建树.根据排序之后的数组,对于一个区间,找到中点的数,将整个区间分为左右 ...

  5. HDU-3743 Minimum Sum,划分树模板

    Minimum Sum 被这个题坑了一下午,原来只需找一个最中间的数即可,我以为是平均数. 题意:找一个数使得这个数和区间内所有数的差的绝对值最小.输出最小值. 开始用线段树来了一发果断T了,然后各种 ...

  6. poj 2104 (划分树模板)

    Description You are working for Macrohard company in data structures department. After failing your ...

  7. POJ2104 K-th Number 划分树 模板题啊

    /*Source Code Problem: 2104 User: 96655 Memory: 14808K Time: 1282MS Language: G++ Result: Accepted S ...

  8. hdu 2665 划分树模板题(可作为模板)

    Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  9. hdu2665 && poj2104划分树

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 47066   Accepted: 15743 Ca ...

随机推荐

  1. android activity中监听View测量完成的4种方式

    在开发中经常碰到需要在activity初始化完成后获得控件大小的情况. 但是这个操作我们不能在oncreate.onresume等生命周期方法中调用,因为我们不知道何时view才能初始化完成 为此,特 ...

  2. 微信a标签不跳转

    [问题] 微信页面开发时,各个主页之间的跳转,完全是通过a链接进行的,但是来回跳转几次,再次从其他主页面跳回首页的时候,微信头部出现了跳转加载进度条,但是就是不跳转,也没有任何反应 [范围] 只出现在 ...

  3. CSS3--阴影,渐变,背景图片

    文字阴影.element{ text-shadow:1px 1px 1px #cccccc;}先右再下第一个值:右侧阴影的大小第二个值:下方阴影的大小第三个值:模糊距离(阴影从开始变淡到完全消失的距离 ...

  4. 发现一个c++ vector sort的bug

    在开发中遇到一个非常诡异的问题:我用vector存储了一组数据,然后调用sort方法,利用自定义的排序函数进行排序,但是一直都会段错误,在排序函数中打印参加排序的值,发现有空值,而且每次都跟同一个数据 ...

  5. android开发技巧

    1 Android去掉listView,gridView等系统自带阴影 当我们使用listView的时候,拉到顶,或是拉到底部的时候,我们会发现有系统自带的阴影效果出现,不同手机出现的颜色可能还会不一 ...

  6. POJ 3416 Crossing

    树状数组+离线操作 #include<stdio.h> #include<string.h> #include<math.h> #include<algori ...

  7. C# 16位的GUDI

    引用:  http://www.cnblogs.com/lcwzj/archive/2009/04/16/1436992.html 当我们想要获得一个唯一的key的时候,通常会想到GUID.这个key ...

  8. @Value 注解获取properties值

    转自:使用Spring 3的@value简化配置文件的读取 Spring 3支持@value注解的方式获取properties文件中的配置值,大简化了读取配置文件的代码. 1.在application ...

  9. html 任意表格

    <!DOCTYPE html><html>    <head>        <meta charset="utf-8" />   ...

  10. LeetCode OJ 189. Rotate Array

    Rotate an array of n elements to the right by k steps. For example, with n = 7 and k = 3, the array  ...