【描述】

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. IE8"开发人员工具"使用详解下(浏览器模式、文本模式、JavaScript调试、探查器)

    来源: http://www.cnblogs.com/JustinYoung/archive/2009/04/03/kaifarenyuangongju2.html 在上一篇文章IE8“开发人员工具” ...

  2. mysql5.7.16安装

    系统:centOS6.5 mysql: 5.7.16 wget http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.16-linux-glib ...

  3. python paramiko模拟ssh登录,实现sftp上传或者下载文件

    Python Paramiko模块的安装与使用详解 paramiko是短链接,不是持续链接,只能执行你设定的shell命令,可以加分号执行两次命令. http://www.111cn.net/phpe ...

  4. Raft协议详解-leader发送心跳代码go

    如果已经把最新的log更新了,那就多等一会,反之,很快就广播AppendEntries(也就是心跳消息) func (rf *Raft) LeaderState() { time.Sleep(10 * ...

  5. android Handler vs Timer

    Handler vs Timer 在我们Android开发过程中,经常需要执行一些短周期的定时任务,这时候有两个选择Timer或者Handler.然而个人认为: Handler 在多个方面比Timer ...

  6. MFC模态和非模态对话框编程

    MFC中对话框有两种形式,一个是模态对话框(model dialog box),一个是非模态对话框(modeless dialog box). 一.模态对话框(model dialog box) 在程 ...

  7. git fetch pull checkout区别

    Git中从远程的分支获取最新的版本到本地有这样2个命令: 1. git fetch:相当于是从远程获取最新版本到本地,不会自动merge <p style="margin-top: 0 ...

  8. LeetCode OJ 92. Reverse Linked List II

    Reverse a linked list from position m to n. Do it in-place and in one-pass. For example:Given 1-> ...

  9. c语言中gets ,getschar 和fgets 的用法及三者之间的差别

    gets——从标准输入接收一串字符,遇到'\n'时结束,但不接收'\n',把 '\n'留存输入缓冲区:把接收的一串字符存储在形式参数指针指向的空间,并在最后自动添加一个'\0'.getchar——从标 ...

  10. 【转】mysql函数

    MySQL函数 MySQL数据库提供了很多函数包括: 数学函数: 字符串函数: 日期和时间函数: 条件判断函数: 系统信息函数: 加密函数: 格式化函数: 一.数学函数 数学函数主要用于处理数字,包括 ...