写在最前:

这道题,其实最节约时间的算法应该是用FC tree,用该数据结构可以在logn的时间内算出来。

但是,说实话,我写不出这样的树出来,至少目前没必要,因为这样太麻烦了,关键是指针不好指。

所以,我用的是2d range tree。用该数据结构可以在logn^2的时间内算出来!

该数据结构的思想为:

1)先创建AVL树,树的每个节点为站点值

2)将站点按x进行从小到大排序,排序完毕之后,依次插入AVL树的叶子节点中。

并且,站点数组的每个数据留一个指针指向最后的叶子节点,方便后面查找用

同时,还将y数组排序好了给每一个节点!

这一段不看也没事

(这里比较神奇的是,最后插完,刚好只有一个叶子节点的一个右孩子是未被插入的,这个在数学上也是可以解释的,因为叶子的孩子节点数之和刚好比总结点数多1)

解释如下:n个节点,有2n个孩子指针。而2n个孩子指针,需要指向n-1个节点(其中有一个被根节点指了),因此剩余n+1个孩子指针。故再次插入n个节点后,剩余1个指针。而我们插入的顺序是由左至右,即由小到大,故最右边的叶子节点的右孩子指针为空。

3)对于每个X1,X2,Y1,Y2。这里我们对x进行2分查找,找到后即可通过预留的指针找到对应的最末端叶子节点

4)然后顺次走到根节点,只需做的是root=root->parent。

这里需要注意的是,每向上走一步,要留一个指针指向原来的位置,这样我们要是想从交点处回来,也方便!

5)找到x1,x2对应的共同节点,然后共同节点往下走,查找每个节点对应的左子树或者右子树即可!

6)对于每颗右子树或者左子树,他们的x值是不用管的,肯定满足,但是y值是要用二分查找找到的,因此需要花费logn的时间

查找到一个y值,就+它的气温,最后得到总气温了!

如果思路还是看不懂,可以详见https://blog.csdn.net/liuqiyao_01/article/details/8478719

或者看图

最后,附上代码!

#pragma warning(disable:4996)
#include <stdio.h>
#include "temperature.h"
#define maxn 50000
using namespace std;
struct range_node;//范围查询的节点构成范围查询树
//station_type是每一个观测站的具体内容(包括了x,y坐标,温度temp,
//观测站内部还有一个指针c,是用来指向叶子节点,然后用来回溯路径)
//一个指针road,用来指向前一个节点
typedef struct _station_type
{int x, y;int temp;_station_type&operator=(const _station_type&data){temp = data.temp;x = data.x;y = data.y;return *this;}range_node*c,*road=NULL;
} station_type;
station_type stations[maxn];
//fctree是用来构建y值数组,每个fctree中都含有station_type类型的data
//y值比较大小,当y值相同时,看x值,这里不可能出现x与y值相同
struct fctree {station_type data;bool operator>(const fctree&a){if (data.y > a.data.y)return true;else if (data.y == a.data.y) {if (data.x > a.data.x)return true;else return false;}else return false;}bool operator<(const fctree&a){if (data.y < a.data.y)return true;else if (data.y == a.data.y) {if (data.x < a.data.x)return true;else return false;}else return false;}
};
//每个节点都有左右指针和对应的y值
//首先要构建AVL树
struct range_node {range_node*rc, *lc, *parent;fctree*fc;//这个指针用于指向y数值的数组,记得初始化时要用new fc来确定它的数组大小int fc_size = 0;station_type data;//每个节点中都只有一个数据点int height = 0;range_node() { rc = lc = NULL; fc = NULL; parent = NULL; }range_node(const station_type&e, range_node*p, fctree*fc1 = NULL, range_node*lc1 = NULL, range_node*rc1 = NULL) :data(e), parent(p), fc(fc1), lc(lc1), rc(rc1) {}
};//构建AVL树---------------------------------------------------------
struct rangetree {//所包含的数据成员;rangetree() { range_node(); }range_node*_hot;//待插入点的父亲节点range_node*_root;//根节点range_node*&search(const int&e);void insertAsRoot(const station_type&e);range_node*insert(const station_type&data);range_node*&fromparento(range_node*g);range_node*connect34(range_node*a, range_node*b, range_node*c, range_node*t0, range_node*t1, range_node*t2, range_node*t3);range_node*rotateAt(range_node*g);void search_leaf(range_node*&v, int&i, range_node*hot);int size = 0;
};
//_station_type的相等是要求x和y都相等
bool operator==(const _station_type&data1, const _station_type&data2)
{return ((data1.x == data2.x) && (data1.y == data2.y));
}
int stature(range_node*a) { return a ? a->height : -1; }//由于a可能为空,因此需要单独给它一个函数
void rangetree::insertAsRoot(const station_type&e)
{_root = new range_node(e, NULL); size++;
}
range_node*&searchin(range_node*&v, const int&e, range_node*&hot)
{if (!v)return v;hot = v;return searchin((e <= v->data.x) ? v->lc : v->rc, e, hot);
}
range_node*&rangetree::search(const int&e)
{//有了_hot=NULL后,就不用每次查询都把_hot重新更新了return searchin(_root, e, _hot = NULL);
}
bool Balance(range_node a) { return (stature(a.lc) - stature(a.rc)) > -2 && stature(a.lc) - stature(a.rc) < 2; }
bool islchild(range_node*g) { return g->parent && (g->parent->lc == g); }
bool isrchild(range_node*g) { return g->parent && (g->parent->rc == g); }
void updateheight(range_node*g)
{if (stature(g->lc)>stature(g->rc)) { g->height = stature(g->lc) + 1; }else { g->height = stature(g->rc) + 1; }
}
range_node*tallerchild(range_node*g)
{return (stature(g->lc) > stature(g->rc)) ? g->lc : (((stature(g->lc) <stature(g->rc)) ? g->rc : (islchild(g) ? g->lc : g->rc)));
}
range_node*&rangetree::fromparento(range_node*g)
{if (g->parent) { return islchild(g) ? g->parent->lc : g->parent->rc; }else { return _root; }
}
range_node*rangetree::insert(const station_type&data)
{range_node*&x = search(data.x);//x不能改变,因为x是引用,x改变,则其父节点的孩子指针也跟着改变,故为了安全起见,不能改变;range_node*xx = x = new range_node(data, _hot);for (range_node*g = _hot; g; g = g->parent){if (!Balance(*g)) {auto&temp = fromparento(g);//=rotateAt(tallerchild(tallerchild(g)));//auto p = tallerchild(g);//auto v = tallerchild(p);temp = rotateAt(tallerchild(tallerchild(g)));break;}else updateheight(g);}size++;return xx;
}
range_node*rangetree::connect34(range_node*a, range_node*b, range_node*c, range_node*t0, range_node*t1, range_node*t2, range_node*t3)
{a->lc = t0; if (t0) { t0->parent = a; }// printf("a->lc= %d\n", a->lc->data.x);a->rc = t1; if (t1) { t1->parent = a; }//printf("a->rc= %d\n", a->rc->data.x);updateheight(a);c->lc = t2; if (t2) { t2->parent = c; } //printf("c->lc= %d\n", c->lc->data.x);c->rc = t3; if (t3) { t3->parent = c; }// printf("c->rc= %d\n", c->rc->data.x);updateheight(c);b->lc = a; a->parent = b;b->rc = c; c->parent = b; updateheight(b);return b;
}
range_node*rangetree::rotateAt(range_node*v)
{range_node*p = v->parent;range_node*g = p->parent;if (islchild(p)) {if (islchild(v)) {p->parent = g->parent;//别忘了parent指针也要记得更新!return connect34(v, p, g, v->lc, v->rc, p->rc, g->rc);}else{v->parent = g->parent;return connect34(p, v, g, p->lc, v->lc, v->rc, g->rc);}}else {if (islchild(v)) {v->parent = g->parent;return connect34(g, v, p, g->lc, v->lc, v->rc, p->rc);}else {p->parent = g->parent;return connect34(g, p, v, g->lc, p->lc, v->lc, v->rc);}}
}
//AVL树构建完毕---------------------------------------------------------bool isleaf(range_node*root) {return root && (!root->lc && !root->rc);
}
int n;
long long int  record = 0;
int count;
station_type stack_x1[100], stack_x2[100];
int road_x1, road_x2;
void merge_y(fctree*&a1, fctree data_lc[], fctree data_rc[], int n_lc, int n_rc)
{a1 = new fctree[n_lc + n_rc];int i = 0, j = 0, k = 0;while (i < n_lc&&j < n_rc){if (data_lc[i] < data_rc[j])a1[k++].data = data_lc[i++].data;else a1[k++].data = data_rc[j++].data;}if (i == n_lc)while (k<n_lc + n_rc){a1[k++].data = data_rc[j++].data;}elsewhile (k<n_lc + n_rc){a1[k++].data = data_lc[i++].data;}
}
//查找叶子节点并且插入对应的x值节点,注意,每插完一次,每个节点的y值也会更新一次
//节点用fctree装y值
void rangetree::search_leaf(range_node*&v, int&i, range_node*hot)
{if (!v) {if (i < n){stations[i].c = v = new range_node(stations[i], hot);v->fc = new fctree[1]; v->fc->data = stations[i++];(v->fc_size)++;}}else {hot = v;search_leaf(v->lc, i, hot);search_leaf(v->rc, i, hot);if (v->lc && v->rc){merge_y(v->fc, v->lc->fc, v->rc->fc, v->lc->fc_size, v->rc->fc_size);v->fc_size = v->lc->fc_size + v->rc->fc_size;}else{v->fc = new fctree[v->lc->fc_size];for (auto i = 0; i < v->lc->fc_size; i++)v->fc[i].data = v->lc->fc[i].data;v->fc_size = v->lc->fc_size;}}
}
//用于对x进行2分查找
void merge_x(station_type data[], int lo, int mi, int hi)
{station_type*a1 = new station_type[mi - lo];int k = lo, i = 0, t = mi - lo;for (auto i = 0; i < mi - lo; i++)a1[i] = data[k++];while ((mi< hi) && (i<t)){if (a1[i].x < data[mi].x)data[lo++] = a1[i++];else if (a1[i].x == data[mi].x&&a1[i].y < data[mi].y)data[lo++] = a1[i++];else data[lo++] = data[mi++];}if (i == t);else while (lo < hi)data[lo++] = a1[i++];delete[]a1;
}
void mergesort_x(station_type data[], int lo, int hi)
{int mi;if (hi - lo > 1) {mi = (hi + lo) >> 1;mergesort_x(data, lo, mi);mergesort_x(data, mi, hi);merge_x(data, lo, mi, hi);}else return;
}
//寻找x1和x2
void search_x1(range_node*root, int x1, int x2, station_type stack[], int&road, int lo, int hi)
{int lenght = hi;while (hi > lo){int mi = (hi + lo) >> 1;(stations[mi].x<x1) ? lo = mi + 1 : hi = mi;}if (lo<lenght&& stations[lo].x <= x2) {auto root = stations[lo].c;while (root){stack[road] = root->data;stack[road].c = root;if (!isleaf(stack[road].c))stack[road].road = stack[road - 1].c;road++;root = root->parent;}}else;
}
void search_x2(range_node*root, int x1, int x2, station_type stack[], int&road, int lo, int hi)
{int lenght = hi;while (hi > lo){int mi = (hi + lo) >> 1;(stations[mi].x > x2) ? hi = mi : lo = mi + 1;}--lo;if (lo > -1 && stations[lo].x >= x1) {auto root = stations[lo].c;while (root){stack[road] = root->data;stack[road].c = root;if (!isleaf(stack[road].c))stack[road].road = stack[road - 1].c;road++;root = root->parent;}}else;
}
//寻找每条路径的公共节点,从该节点开始回溯
range_node*common_root()
{while (0 < road_x1 && 0 < road_x2&&stack_x1[--road_x1] == stack_x2[--road_x2]);return (stack_x1[road_x1] == stack_x2[road_x2]) ? stack_x1[road_x1].c : stack_x1[++road_x1].c;
}
//对每个节点的y值进行2分查找!
void search_y(range_node*root, int lo, int hi, int y1, int y2)
{while (lo < hi){int mi = (lo + hi) >> 1;(y1 <= root->fc[mi].data.y) ? hi = mi : lo = mi + 1;}while (lo < root->fc_size&&root->fc[lo].data.y <= y2  ){record += root->fc[lo].data.temp;count++;lo++;}
}
void travelReport(int x1,int x2,int y1, int y2)
{while (road_x1 >= 0){auto rc = stack_x1[road_x1].c->rc;auto lc = stack_x1[road_x1].c->lc;auto road = stack_x1[road_x1].road;if (rc&&rc!=road)search_y(rc, 0, rc->fc_size, y1, y2);road_x1--;}auto now = stack_x1[road_x1 + 1].c;if (now->data.x >= x1 &&now->data.x <= x2 && now->data.y >= y1 && now->data.y <= y2){count++;record += now->data.temp;}while (road_x2 >= 0){auto rc = stack_x2[road_x2].c->rc;auto lc = stack_x2[road_x2].c->lc;auto road = stack_x2[road_x2].road;if (lc&&lc != road)search_y(lc, 0, lc->fc_size, y1, y2);road_x2--;}auto now2 = stack_x2[road_x2 + 1].c;if (now2->data.x >= x1 && now2->data.x <= x2 && now2->data.y >= y1 && now2->data.y <= y2){count++;record += now2->data.temp;}
}
//先序和中序遍历用来保证AVL树的正确构建-----------------------------------------------------------------
void xianxutravel(range_node*r)
{printf("%d(%d)\n", r->data.x, r->data.y);if (r->lc)xianxutravel(r->lc);if (r->rc)xianxutravel(r->rc);
}
void midtravel(range_node*r)
{if (r->lc)midtravel(r->lc);printf("%d(%d)\n", r->data.x, r->data.y);if (r->rc)midtravel(r->rc);
}
int main()
{n = GetNumOfStation();if (n == 0) {int x1, x2, y1, y2;while (GetQuery(&x1, &y1, &x2, &y2)) {Response(0); printf("0\n");}return 0;}rangetree a;for (auto i = 0; i < n; i++)GetStationInfo(i, &(stations[i].x), &(stations[i].y), &(stations[i].temp));a.insertAsRoot(stations[0]);for (auto i = 1; i < n; i++)a.insert(stations[i]);//为了防止出现先大的插入导致后面小的没有位置,所以得先排序;mergesort_x(stations, 0, n);int i = 0;a._hot = NULL;a.search_leaf(a._root, i, a._hot);//先序和中序遍历//midtravel(a._root);//printf("--------------\n");//xianxutravel(a._root);int x1, x2, y1, y2, num = 1;while (GetQuery(&x1, &y1, &x2, &y2)){search_x1(a._root, x1, x2, stack_x1, road_x1, 0, n);//取消注释可以看到路径//printf("road%d:= ", num);//for (auto i = 0; i < road_x1; i++) { printf("%d(%d) ", stack_x1[i].x, stack_x1[i].y); }//printf("\n");search_x2(a._root, x1, x2, stack_x2, road_x2, 0, n);//printf("road%d:= ", num++);//printf("%d,%d\n", road_x1, road_x2);//for (auto i = 0; i < road_x2; i++) { printf("%d(%d) ", stack_x2[i].x, stack_x2[i].y); }//printf("\n");int t1 = road_x1, t2 = road_x2;if (road_x1&&road_x2){range_node*v = common_root();//取消注释可以看到公共节点//printf("%d,%d\n", road_x1, road_x2);//printf("v= %d(%d)\n", v->data.x, v->data.yroad_x1--;travelReport(x1,x2,y1, y2);//printf("count = %d\n", count);if (count != 0) {Response(record / count);//取消注释可以直接看到输出//printf("%d\n", record / count);//printf("count= %d\n", count);}else {Response(0);//printf("0\n");}}else {Response(0);//printf("0\n");}for (auto i = 0; i < t1; i++) { stack_x1[i].c = NULL; stack_x1[i].road = NULL; stack_x1[i].x = 0; stack_x1[i].y = 0; stack_x1[i].temp = 0; }for (auto i = 0; i <t2; i++) { stack_x2[i].c = NULL; stack_x1[i].road = NULL; stack_x2[i].x = 0; stack_x2[i].y = 0; stack_x2[i].temp = 0; }t1 = t2 = road_x1 = road_x2 = record = count = 0;}
}

然后是temperature.in的内容

13 6
1   0   1000
3   0   1300
2   0   1600
-5  0   1100
-8  0   1200
0   0   2300
3   4   2212
4   4   3209
-4  2   1234
-1  4   1223
0   8   3212
0   3   2332
-2147483648 2147483647 1236
-8 0 6 0
-6 0 4 2
4 2 23 123
3 2 12 12
-1 9 2 10
-2147483648 -2147483648 2147483647 2147483647

最后附上100分的图。

我真的,搞了好久,才做出这题QAQ。附注,kd-tree不能解决该题,因为时间复杂度为,太长了。。。

清华数据结构平均气温AC100相关推荐

  1. 清华数据结构列车调度AC100分

    两种思路 (1)将目标栈的数据和待混洗的数据逐个进行比较 #pragma warning(disable:4996) #include<stdio.h> #include<strin ...

  2. 清华数据结构无线广播AC100

    #pragma warning(disable:4996) #include<stdio.h> using namespace std; #define maxn 10000 #defin ...

  3. MOOC数据结构(下)(自主模式)-平均气温(Temperature)

    平均气温(Temperature) Description A weather station collects temperature data from observation stations ...

  4. 平均气温(Temperature)

    平均气温(Temperature) Description A weather station collects temperature data from observation stations ...

  5. PA8题解报告——平均气温(Temperature)

    数据结构与算法实验2020夏第二批(中国石油大学) PA8题解报告--平均气温(Temperature) 目录 题目描述 题目分析 编码实现 一.题目描述 1. 题目描述 某气象台每天都要从遍布于各地 ...

  6. 各纬度气候分布图_读我国一月平均气温分布图,寻找我国冬季气温最高和最低的地方...

    地图是地理学的语言,地图能够科学地反映出自然和社会经济现象的分布特征及其相互关系,所以我们阅读地图也能获取许多的地理信息.之前我们已经通过读中国年平均气温分布图.世界年降水量分布图.世界年平均气温分布 ...

  7. 各纬度气候分布图_读中国年平均气温分布图,寻找中国全年平均气温最高和最低的地方...

    自然地理环境包括地形.气候.土壤.植被和水文等要素,一个地区的气候又是由气温.降水.光照等要素来组成的.在分析一个地区的气温特征时,我们主要从年均温和气温年较差两个角度来入手,影响气温高低的因素有很多 ...

  8. 利用Excel VBA批量计算气象数据多个台站多年来春季和冬季降水量和平均气温

    气象数据是地理数据的重要组成部分,存储量虽然不大,但是处理过程非常繁琐,长时序数据更不用说.本文总结了一个气象数据的基本处理方法. 如下图所示,气象数据的排列格式是区站号→年→月→降水量→平均气温,时 ...

  9. 运用自回归滑动平均模型、灰色预测模型、BP神经网络三种模型分别预测全球平均气温,并进行预测精度对比(附代码、数据)

    大家好,我是带我去滑雪,每天教你一个小技巧!全球变暖是近十年来,人们关注度最高的话题.2022年夏天,蔓延全球40℃以上的极端天气不断刷新人们对于高温的认知,人们再也不会像从前那样认为全球变暖离我们遥 ...

最新文章

  1. RuntimeError: dictionary changed size during iteration 解决办法
  2. 独家 | 人工智能和大数据是如何联系在一起的?
  3. 利用 GPU 加速人工智能:新型计算模式
  4. PHP Log时时查看小工具
  5. linux 查端口 三种,Linux查看端口常用的三种用例
  6. 修改Linux字体出现乱码
  7. 洛谷 - P2765 魔术球问题(最大流+残余网络上的最大流+路径打印)
  8. python插件使用教程_Python常用扩展插件使用教程解析
  9. linux tomcat 启动权限不足解决办法
  10. 芝麻当家运营级商城源码/H5/小程序/网页
  11. Linux的Application 内存模型---
  12. 诗与远方:无题(四十八)
  13. 一个设置容器和网格布局的小技巧
  14. SQL SERVER游标浅析
  15. 剑指offer(C++)-JZ25:合并两个排序的链表(数据结构-链表)
  16. TCP三次握手与四次挥手的过程及原因
  17. LeetCode962. 最大宽度坡
  18. android连接打印机打印pdf文件,在android中打印pdf
  19. html 免备案,域名没有备案使用cdn(免备案cdn推荐)
  20. NAudio:MP3转WAV和Wav转Mp3

热门文章

  1. 七彩跑马闪光灯方案开发 MCU产品开发
  2. 2023研考国家线发布?未上岸的你还有人大与加拿大女王大学金融硕士可选择
  3. devexpress控件教程 开发workflow设计器这么简单
  4. 中国现代最深刻的学者思想家——秦晖老师!(执教于清华大学历史系)
  5. java订单编号工具类_[idmiss-common] Java 工具类之- 顺序订单号的生成
  6. 【清华大学】操作系统 陈渝——Part6 全局页面置换算法
  7. 3dmax渲染全景图生成行走式漫游效果(一)
  8. 无纸化会议私有化部署需要哪些设备?
  9. 轩小宝进城记~~ 2012年3月24日
  10. android note4 android版本,三星Note 4可升级Android 5.1.1:体验不如三星S6