【描述】

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. mysql创建计算列

    mysql> create table t(id int auto_increment not null,c1 int,c2 int,c3 int as (c1+c2),primary key( ...

  2. 进入BIOS SHELL DUMP 命令

    LINUX系统 进入SHELL 输入命令 fs1: or fs0: 就进入了U盘目录 然后输入 ACPIRW.efi  -d -s dsdt.bat 就会产生结果到U盘 ——————————————— ...

  3. Spring 表单提交,后台自动封装有集合对象的对象

    from表单: <form action="${pageContext.request.contextPath}/vote/save" method="post&q ...

  4. 安装阿里云的php+mysql+nginx+vsftpd

    百度云search   sh-1.3.0-centos.zip

  5. SharePoint2013 Set Value To PeoplePicker

    var columnName = 'Display Name';var userName = 'domain\\name';var searchText = RegExp("FieldNam ...

  6. Linux教程之配置权限受限制的SFTP

    SFTP 在Linux下是一个很方便很安全的文件传输工具,我常常用它在Linux服务器上替代传统的ftp来传输文件.众所周知SFTP账号是基于SSH账号的,默认情况下访问服务器的权限很大,下面的教程就 ...

  7. JSP内置对象--4种属性范围 (pageContext,request,session,application)

    pageContext: javax.servlet.jsp.JspContext抽象类的父类JspContext 中有以下方法. request:javax.servlet.http.的接口Http ...

  8. PHP运行模式(cgi,fast-cgi,cli, ISAPI ,web模块模式)【转载】

    PHP运行模式有5钟: 1)cgi 通用网关接口(Common Gateway Interface))2)fast-cgi 常驻 (long-live) 型的 CGI3)cli  命令行运行   (C ...

  9. MySQL的索引创建、删除

    1_1.添加PRIMARY KEY(主键索引)  mysql>ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` ) 1_2.添加UNIQUE ...

  10. Python 协程/异步IO/Select\Poll\Epoll异步IO与事件驱动

    1 Gevent 协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到 ...