二维线段树(hdu1823)

二维线段树其实也没有其他新知识,从名字上也能看出,他不过就是将一维变成二维,把之前的一维线段树每个节点再扩展成一棵线段树如下图:

图上红标号点是一维树,蓝标号点就是二维树。

从图也可看出,我们之所以要用二维线段树是因为你要得到的答案限制条件用一维无法控制,而二维线段树可以在满足一维线段树条件的情况下在二维还可以有给我们限制条件的空间,最终就可以从一维到二维再到答案。

图看起来比一维线段树多了好多分支,但是对他进行操作时其实和一维的没什么两样,就是在满足一维条件情况下对二维进行操作。

看代码你就知道了(代码是我在知道二维线段树的大概思路后自己写的,可能比较丑,不过题目都ac了,应该没有错,建议大家自己先写实现一遍)

hdu1823:http://acm.hdu.edu.cn/showproblem.php?pid=1823

中文题,题意就不说了

思路就是线段树一维存身高,二维存活跃度和缘分,将一位小数乘10化为整数。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 #include<algorithm>
  5 #include<string>
  6 #include<string.h>
  7 #include<map>
  8 #include<vector>
  9 #include<cmath>
 10 #include<iterator>
 11 #define mem(a,b) memset(a,b,sizeof(a))
 12 #define MOD 100000007
 13 #define LL long long
 14 #define INF 0x3f3f3f3f
 15 const double pi = acos(-1.0);
 16 const int Maxn=101;
 17 using namespace std;
 18 struct Tree{//二维树 
 19     int l,r;
 20     int mh;
 21 };
 22 struct Mtree{//一维树 
 23     int l,r;
 24     struct Tree tree[Maxn*4*10];
 25 }mt[Maxn*4];
 26 void Btree(int mk,int k,int l,int r){//二维树的建树操作 
 27     mt[mk].tree[k].l=l,mt[mk].tree[k].r=r;
 28     if(l==r){
 29         mt[mk].tree[k].mh=-1;
 30         return ;
 31     }
 32     int mid=(l+r)>>1;
 33     Btree(mk,k<<1,l,mid);
 34     Btree(mk,k<<1|1,mid+1,r);
 35     mt[mk].tree[k].mh=max(mt[mk].tree[k<<1].mh,mt[mk].tree[k<<1|1].mh);
 36 }
 37 void BMtree(int k,int l,int r){//一维树的建树操作 
 38     mt[k].l=l,mt[k].r=r;
 39     Btree(k,1,0,1000);//这里就是从一维节点对二维树进行建立 
 40     if(l==r){
 41         return ;
 42     }
 43     int mid=(l+r)>>1;
 44     BMtree(k<<1,l,mid);
 45     BMtree(k<<1|1,mid+1,r);
 46 }
 47 void addP_tree(int mk,int k,int A,int L){//二维树的节点更新 
 48     if(mt[mk].tree[k].l==mt[mk].tree[k].r&&mt[mk].tree[k].l==A){
 49         mt[mk].tree[k].mh=max(L,mt[mk].tree[k].mh);//不能覆盖,可能会有输入的出缘分值其他都相同的情况 
 50         return ;
 51     }
 52     int mid=(mt[mk].tree[k].l+mt[mk].tree[k].r)>>1;
 53     if(mid>=A){
 54         addP_tree(mk,k<<1,A,L);
 55     }else{
 56         addP_tree(mk,k<<1|1,A,L);
 57     }
 58     mt[mk].tree[k].mh=max(mt[mk].tree[k<<1].mh,mt[mk].tree[k<<1|1].mh);
 59 }
 60 void addP_mt(int k,int H,int A,int L){//从一维树找到符合条件的节点,再进去对二维树进行更新 
 61     if(mt[k].l==mt[k].r&&mt[k].l==H){
 62         addP_tree(k,1,A,L);//二维更新 
 63         return ;
 64     }    
 65     int mid=(mt[k].l+mt[k].r)>>1;
 66     if(mid>=H){
 67         addP_mt(k<<1,H,A,L); 
 68     }else{
 69         addP_mt(k<<1|1,H,A,L);
 70     }
 71     addP_tree(k,1,A,L);//回溯时对该点相关父点更新 
 72 }
 73 int ans;
 74 void query_tree(int mk,int k,int al,int ar){//查询 
 75     if(mt[mk].tree[k].l>=al&&mt[mk].tree[k].r<=ar){
 76         ans=max(mt[mk].tree[k].mh,ans);
 77         return ;
 78     }
 79     int mid=(mt[mk].tree[k].l+mt[mk].tree[k].r)>>1;
 80     if(ar<=mid){
 81         query_tree(mk,k<<1,al,ar);
 82     }else if(al>mid){
 83         query_tree(mk,k<<1|1,al,ar);
 84     }else{
 85         query_tree(mk,k<<1,al,ar);
 86         query_tree(mk,k<<1|1,al,ar);
 87     }
 88 }
 89 void query_mt(int k,int hl,int hr,int al,int ar){
 90     if(mt[k].l>=hl&&mt[k].r<=hr){
 91         query_tree(k,1,al,ar);//子树询问
 92         return ; 
 93     }
 94     int mid=(mt[k].l+mt[k].r)>>1;
 95     if(hr<=mid){
 96         query_mt(k<<1,hl,hr,al,ar);
 97     }else if(mid<hl){
 98         query_mt(k<<1|1,hl,hr,al,ar);
 99     }else{
100         query_mt(k<<1,hl,hr,al,ar);
101         query_mt(k<<1|1,hl,hr,al,ar);
102     }
103 }
104 int main(){
105     int n;
106     char s[5];
107     int H,H1,H2;
108     double A,L,A1,A2;
109     while(~scanf("%d",&n)&&n){
110         mem(mt,0);
111         BMtree(1,100,200);
112         while(n--){
113             scanf("%s",s);
114             if(s[0]=='I'){
115                 scanf("%d%lf%lf",&H,&A,&L);
116                 addP_mt(1,H,(int)(A*10),(int)(L*10));
117             }else if(s[0]=='Q'){
118                 scanf("%d%d%lf%lf",&H1,&H2,&A1,&A2);
119                 ans=-1;
120                 query_mt(1,min(H1,H2),max(H1,H2),min((int)(A1*10),(int)(A2*10)),max((int)(A1*10),(int)(A2*10)));//这是这题目中的一个坑,注意!!!! 
121                 if(ans!=-1)
122                 printf("%.1lf\n",(double)(ans*1.0/10));
123                 else
124                 printf("-1\n");
125             }
126         }
127     }
128     return 0;
129 }
View Code

二维线段树的空间复杂度一看就高了很多,所以题目一般数据都不是特大

有错请指正。

猜你喜欢

转载自www.cnblogs.com/liuzuolin/p/10548855.html
0条评论
添加一条新回复