POJ 2761 Feed the dogs
2014-02-28 21:18
288 查看
题目大意:
Wind爱狗,并且有n条狗(n < 100,001),佳佳不爱狗,但是爱Wind,所以他每天需要替Wind喂狗。当然了,他自有特别的喂狗方式,每到中饭时间够就会按照编号站成一排,从左到有一次为1, 2, 3...n号,每条狗都会被佳佳赋予一个“可爱值”,可爱值互不相同,喂的时候佳佳会先选出一个编号区间[i号-j号],然后在该区间中选择“可爱值”第k大的狗喂食,这样可以避免多次喂同样几条狗导致狗被喂死(这会让Wind大发雷霆,后果很严重)。
喂食会有m次(m < 50,001),每次都会指定选择区间(i, j)和k(区间内“可爱值”第k大的狗),先求出每次被喂食的狗的“可爱值”,选中的区间可能会相互重叠,只有一个测例。
题目链接
使用规模平衡二叉树SBT(Size Balanced Tree):
注释代码:
无注释代码:
单词解释:
pretty:adj, 漂亮的,可爱的
lunchtime:n, 午饭时间
leftmost/rightmost:adj, 最左边的/左右边的
afterefftect:n, 后果
hence:adj, 因此
intersect with:和...相交
Wind爱狗,并且有n条狗(n < 100,001),佳佳不爱狗,但是爱Wind,所以他每天需要替Wind喂狗。当然了,他自有特别的喂狗方式,每到中饭时间够就会按照编号站成一排,从左到有一次为1, 2, 3...n号,每条狗都会被佳佳赋予一个“可爱值”,可爱值互不相同,喂的时候佳佳会先选出一个编号区间[i号-j号],然后在该区间中选择“可爱值”第k大的狗喂食,这样可以避免多次喂同样几条狗导致狗被喂死(这会让Wind大发雷霆,后果很严重)。
喂食会有m次(m < 50,001),每次都会指定选择区间(i, j)和k(区间内“可爱值”第k大的狗),先求出每次被喂食的狗的“可爱值”,选中的区间可能会相互重叠,只有一个测例。
题目链接
使用规模平衡二叉树SBT(Size Balanced Tree):
注释代码:
/* * Problem ID : POJ 2761 Feed the dogs * Author : Lirx.t.Una * Language : C++ * Run Time : 2032 ms * Run Memory : 3248 KB */ #include <stdlib.h> #include <stdio.h> //表示树的结点为空 #define NILL 0 #define TRUE 1 #define FALSE 0 //maximum number of dogs //狗的最大数量 #define MAXDOGN 100001 //maximum number of feedings //喂食的最大次数 #define MAXFEEDN 50001 struct BFeeding {//Feeding body, //关于喂食的结构体 int l;//left,喂食的区间左端 int r;//right,喂食的区间右端 int k;//选择可爱值第k大的狗进行喂食 int ord;//ordinal,指明本次是第几次喂食 }; typedef struct BFeeding Feeding; typedef struct BFeeding * Feed; typedef struct BFeeding ** PtFeed; typedef int BOOL; typedef int Tree;//使用数组实现SBT Feeding bf[MAXFEEDN]; Feed f[MAXFEEDN]; int ans[MAXFEEDN];//存放每次喂食的答案 //即每次第k大的狗的可爱值 //以下四项为SBT树中的结点 //其中树结点i中包含了四个域 //key[i]可爱值 //siz[i]即size,即该棵树的大小(总共包含几个结点) //lft[i]、rht[i],该结点的左右子树 int key[MAXDOGN] = { 0 }; int siz[MAXDOGN] = { 0 }; Tree lft[MAXDOGN] = { NILL }; Tree rht[MAXDOGN] = { NILL }; int dog[MAXDOGN];//dog[i]表示第i条狗的可爱值 Tree RotL(Tree k2) {//AVL左旋 Tree k1; k1 = lft[k2]; lft[k2] = rht[k1]; rht[k1] = k2; siz[k1] = siz[k2]; siz[k2] = siz[ lft[k2] ] + siz[ rht[k2] ] + 1; return k1; } Tree RotR(Tree k2) {//AVL右旋 Tree k1; k1 = rht[k2]; rht[k2] = lft[k1]; lft[k1] = k2; siz[k1] = siz[k2]; siz[k2] = siz[ lft[k2] ] + siz[ rht[k2] ] + 1; return k1; } Tree RotLR(Tree t) {//AVL左右双旋 rht[t] = RotL( rht[t] ); return RotR(t); } Tree RotRL(Tree t) {//AVL右左双旋 lft[t] = RotR( lft[t] ); return RotL(t); } Tree Maintain( Tree tree, BOOL cmp ) {//维护 //SBT的插入其实都是普通的BST插入,在每次 //插入后都会使用该函数对SBT树进行维护 //以调整它的高度,使之平衡 if ( cmp )//表示插入的可爱值k小于tree结点的可爱值 //此时该结点必定插入到了tree的左子树,因此需要 //检查左子树是否过大 if ( siz[ lft[ lft[tree] ] ] > siz[ rht[tree] ] ) tree = RotL(tree);//若左子树的左子树规模大于右子树则需左旋 else if ( siz[ rht[ lft[tree] ] ] > siz[ rht[tree] ] ) tree = RotRL(tree);//若左子树的右子树规模大于右子树则需右左旋 else return tree;//否则就表示满足平衡条件,可以直接退出函数 else//对于插入到右子树的情形也是相同的 if ( siz[ rht[ rht[tree] ] ] > siz[ lft[tree] ] ) tree = RotR(tree); else if ( siz[ lft[ rht[tree] ] ] > siz[ lft[tree] ] ) tree = RotLR(tree); else return tree; //即使旋转过也并不代表概述一定就满足平衡条件了,需要继续探测并调整 //当旋转后左右子仍存在的,则继续向树的最外两侧探测和调整 if ( lft[tree] ) lft[tree] = Maintain( lft[tree], TRUE ); if ( rht[tree] ) rht[tree] = Maintain( rht[tree], FALSE ); //此时左右子树已经完美平衡了,但顶点本身可能离平衡只有微小的距离 //因此此次维护只是做一点点微调,不会耗多少时间的 tree = Maintain( tree, TRUE );//左微调一次 return Maintain( tree, FALSE );//最后再右微调一次 } Tree Insert( Tree tree, int node, int k ) { if ( !tree ) { key[node] = k; siz[node] = 1; lft[node] = NILL; rht[node] = NILL; return node; } siz[tree]++; if ( k < key[tree] ) lft[tree] = Insert( lft[tree], node, k ); else rht[tree] = Insert( rht[tree], node, k ); //到这之前都是很平常的BST插入 return Maintain( tree, k < key[tree] ); } Tree Remove( Tree tree, int k ) { if ( !tree ) return NILL; siz[tree]--;//由于题目的限制,每次删除的结点 //必定都在树中,因此不需要再写Find函数判断 //待删的结点是否在树中了,因此可以直接-- if ( k == key[tree] ) {//若当前结点就是待删结点 if ( !lft[tree] || !rht[tree] )//对于左右子树有空的 return lft[tree] + rht[tree];//直接返回非空的 //或者两者都是空的,则就直接删除即可 int node; //若左右子树都非空,则可以将左子树中最大的结点 //即右下角的结点作为根结点(树顶)代替老的树顶 //然后再删除该结点就行了 //先找到该结点(由于它是左子树中最大的结点,因此可以作为新树顶) node = lft[tree]; while ( rht[node] ) node = rht[node]; key[tree] = key[node];//替代 lft[tree] = Remove( lft[tree], key[node] );//再删除该结点 return tree; } if ( k < key[tree] ) lft[tree] = Remove( lft[tree], k ); else rht[tree] = Remove( rht[tree], k ); return tree; } int Rank( Tree tree, int k ) {//按照可爱值大小排名 int mid; mid = siz[ lft[tree] ] + 1;//树顶是第mid大的 if ( k == mid ) return key[tree]; if ( k < mid ) return Rank( lft[tree], k ); else return Rank( rht[tree], k - mid ); } int fcmp(const void *a, const void *b) { Feed fa, fb; fa = *(PtFeed)a; fb = *(PtFeed)b; //排序时按照喂食区间的左端从小到大排 if ( fa->l - fb->l ) return fa->l - fb->l; else//若左端相等则按照右端从小到大排 return fa->r - fb->r; } int main() { int n, m;//狗总数和喂食总次数 int i, j;//计数变量 int l, r;//先区间left - right int pl, pr;//上衣区间previous left - previous right int node;//插入的结点号 Tree tree;//SBT树 scanf("%d%d", &n, &m); for ( i = 1; i <= n; i++ ) scanf("%d", dog + i); for ( i = 1; i <= m; i++ ) { scanf("%d%d%d", &bf[i].l, &bf[i].r, &bf[i].k); bf[i].ord = i; f[i] = bf + i;//利用指针数组对原数组排序,省时间 } //具体做法是对于每个区间,都构建一个该区间的SBT树 //然后对该数求rank,即可得到第k大的狗了 //但是为了避免重复构建相同区间的SBT(或者是重合的) //对喂食进行排序(左端从小到大,若相同则右端从小到大) //可以避免对重叠的区间重复构造SBT树 qsort(f + 1, m, sizeof(Feed), &fcmp); //初始化 tree = NILL; node = 0; pl = 1; pr = 0; for ( i = 1; i <= m; i++ ) { l = f[i]->l; r = f[i]->r; //×表示该区间需要删除 //*表示该区间需要构建 //空表示该区间什么都不用做 //不变表示该区间保留,无需删除和构建 if ( l > pr ) {// pl×××pr 空 l****r for ( j = pl; j <= pr; j++ ) tree = Remove( tree, dog[j] ); for ( j = l; j <= r; j++ ) tree = Insert( tree, ++node, dog[j] ); } else if ( r > pr ) {// pl×××l 不变 pr****r for ( j = pl; j < l; j++ ) tree = Remove( tree, dog[j] ); for ( j = pr + 1; j <= r; j++ ) tree = Insert( tree, ++node, dog[j] ); } else {// pl×××l 不变 r×××pr for ( j = pl; j < l; j++ ) tree = Remove( tree, dog[j] ); for ( j = pr + 1; j < r; j++ ) tree = Remove( tree, dog[j] ); } pl = l; pr = r; ans[ f[i]->ord ] = Rank( tree, f[i]->k ); } for ( i = 1; i <= m; i++ ) printf("%d\n", ans[i]); return 0; }
无注释代码:
#include <stdlib.h> #include <stdio.h> #define NILL 0 #define TRUE 1 #define FALSE 0 #define MAXDOGN 100001 #define MAXFEEDN 50001 struct BFeeding { int l; int r; int k; int ord; }; typedef struct BFeeding Feeding; typedef struct BFeeding * Feed; typedef struct BFeeding ** PtFeed; typedef int BOOL; typedef int Tree; Feeding bf[MAXFEEDN]; Feed f[MAXFEEDN]; int ans[MAXFEEDN]; int key[MAXDOGN] = { 0 }; int siz[MAXDOGN] = { 0 }; Tree lft[MAXDOGN] = { NILL }; Tree rht[MAXDOGN] = { NILL }; int dog[MAXDOGN]; Tree RotL(Tree k2) { Tree k1; k1 = lft[k2]; lft[k2] = rht[k1]; rht[k1] = k2; siz[k1] = siz[k2]; siz[k2] = siz[ lft[k2] ] + siz[ rht[k2] ] + 1; return k1; } Tree RotR(Tree k2) { Tree k1; k1 = rht[k2]; rht[k2] = lft[k1]; lft[k1] = k2; siz[k1] = siz[k2]; siz[k2] = siz[ lft[k2] ] + siz[ rht[k2] ] + 1; return k1; } Tree RotLR(Tree t) { rht[t] = RotL( rht[t] ); return RotR(t); } Tree RotRL(Tree t) { lft[t] = RotR( lft[t] ); return RotL(t); } Tree Maintain( Tree tree, BOOL cmp ) { if ( cmp ) if ( siz[ lft[ lft[tree] ] ] > siz[ rht[tree] ] ) tree = RotL(tree); else if ( siz[ rht[ lft[tree] ] ] > siz[ rht[tree] ] ) tree = RotRL(tree); else return tree; else if ( siz[ rht[ rht[tree] ] ] > siz[ lft[tree] ] ) tree = RotR(tree); else if ( siz[ lft[ rht[tree] ] ] > siz[ lft[tree] ] ) tree = RotLR(tree); else return tree; if ( lft[tree] ) lft[tree] = Maintain( lft[tree], TRUE ); if ( rht[tree] ) rht[tree] = Maintain( rht[tree], FALSE ); tree = Maintain( tree, TRUE ); return Maintain( tree, FALSE ); } Tree Insert( Tree tree, int node, int k ) { if ( !tree ) { key[node] = k; siz[node] = 1; lft[node] = NILL; rht[node] = NILL; return node; } siz[tree]++; if ( k < key[tree] ) lft[tree] = Insert( lft[tree], node, k ); else rht[tree] = Insert( rht[tree], node, k ); return Maintain( tree, k < key[tree] ); } BOOL Find( Tree tree, int k ) { if ( !tree ) return FALSE; if ( k == key[tree] ) return TRUE; if ( k < key[tree] ) return Find( lft[tree], k ); else return Find( rht[tree], k ); } Tree Remove( Tree tree, int k ) { if ( !tree ) return NILL; siz[tree]--; if ( k == key[tree] ) { if ( !lft[tree] || !rht[tree] ) return lft[tree] + rht[tree]; int node; node = lft[tree]; while ( rht[node] ) node = rht[node]; key[tree] = key[node]; lft[tree] = Remove( lft[tree], key[node] ); return tree; } if ( k < key[tree] ) lft[tree] = Remove( lft[tree], k ); else rht[tree] = Remove( rht[tree], k ); return tree; } int Rank( Tree tree, int k ) { int mid; mid = siz[ lft[tree] ] + 1; if ( k == mid ) return key[tree]; if ( k < mid ) return Rank( lft[tree], k ); else return Rank( rht[tree], k - mid ); } int fcmp(const void *a, const void *b) { Feed fa, fb; fa = *(PtFeed)a; fb = *(PtFeed)b; if ( fa->l - fb->l ) return fa->l - fb->l; else return fa->r - fb->r; } int main() { int n, m; int i, j; int l, r; int pl, pr; int node; Tree tree; scanf("%d%d", &n, &m); for ( i = 1; i <= n; i++ ) scanf("%d", dog + i); for ( i = 1; i <= m; i++ ) { scanf("%d%d%d", &bf[i].l, &bf[i].r, &bf[i].k); bf[i].ord = i; f[i] = bf + i; } qsort(f + 1, m, sizeof(Feed), &fcmp); tree = NILL; node = 0; pl = 1; pr = 0; for ( i = 1; i <= m; i++ ) { l = f[i]->l; r = f[i]->r; if ( l > pr ) { for ( j = pl; j <= pr; j++ ) tree = Remove( tree, dog[j] ); for ( j = l; j <= r; j++ ) tree = Insert( tree, ++node, dog[j] ); } else if ( r > pr ) { for ( j = pl; j < l; j++ ) tree = Remove( tree, dog[j] ); for ( j = pr + 1; j <= r; j++ ) tree = Insert( tree, ++node, dog[j] ); } else { for ( j = pl; j < l; j++ ) tree = Remove( tree, dog[j] ); for ( j = pr + 1; j < r; j++ ) tree = Remove( tree, dog[j] ); } pl = l; pr = r; ans[ f[i]->ord ] = Rank( tree, f[i]->k ); } for ( i = 1; i <= m; i++ ) printf("%d\n", ans[i]); return 0; }
单词解释:
pretty:adj, 漂亮的,可爱的
lunchtime:n, 午饭时间
leftmost/rightmost:adj, 最左边的/左右边的
afterefftect:n, 后果
hence:adj, 因此
intersect with:和...相交
相关文章推荐
- Your Ubuntu 12.04 is running in 2D mode,Many features will not be available.(on Ubuntu 12.04)解决方法
- json
- 图片滚动标签 html
- MVC JS 框架
- 页面校验用通用js
- JQuery判断checkbox是否选中
- jquery 操作select
- bower install js使用bower管理js
- js解决dwz数据传输问题
- Thread-safety with regular expressions in Java
- JSP 9 大内置对象详解
- CoffeeScript 简介与安装步骤概览
- 应该重新审视的javascript
- SharePoint 2013 开发中JavaScript本地化方案
- Extjs 动态生成表格
- C# Json格式转换成List集合
- Json转换神器之Google Gson的使用
- HTML学习笔记
- HTML前端技术(JS的使用,包括数组和字符串)
- HTML前端技术(JS的使用,包括数组和字符串)