【描述】

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. javaScript中的一些知识

    利用js动态生成table <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http ...

  2. svn hooks的使用demo

    我是理论家: svn server端提供了Hooks Script.所谓钩子实际上是一种时间触发机制,是指当系统执行到某个特殊的事件时,触发我们预定义的动作,可以让我们在某些特定状态发生的时候做我们想 ...

  3. NEU OJ 1651 Great number

    循环节是2000000016 字符串读入,用一下高精度对2000000016取个模,用一下快速幂就可以算出答案了. #include <cstdio> #include <iostr ...

  4. git 免密码提交代码

    Linux或者Mac下方法: 创建文件,进入文件,输入内容: cd ~ touch .git-credentials vim .git-credentials https://{username}:{ ...

  5. 如何在MFC中启动其它的(.exe)可执行文件

    ShellExecute(NULL,   "open",   "http://www.sina.com.cn",   NULL,   NULL,   SW_SH ...

  6. HUD1862:EXCEL排序

    Problem Description Excel可以对一组纪录按任意指定列排序.现请你编写程序实现类似功能.   Input 测试输入包含若干测试用例.每个测试用例的第1行包含两个整数 N (< ...

  7. HDU1062:Text Reverse

    Problem Description Ignatius likes to write words in reverse way. Given a single line of text which ...

  8. AC Me

    AC Me Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Submiss ...

  9. differences between null pointer and void pointer.

    These are two different concepts, you cannot compare them. What the difference between the skunk and ...

  10. Razor Engine,动态脚本语言,mvc上的语法,适用于文件内容生成,静态网页生成等。

    https://razorengine.codeplex.com/ 下载并引用:razorengine.dll 代码里这样写,用mvc的人都会!Razor语法! string template = & ...