HDU 5820 (可持久化线段树)

Problem Lights (HDU 5820)

题目大意

  在一个大小为50000*50000的矩形中,有n个路灯。(n<=500000)

  询问是否每一对路灯之间存在一条道路,使得长度为|x1 – x2| + |y1 – y2|且每个拐弯点都是路灯。

解题分析

  官方题解:

     

  除了从左往右扫描一遍外,个人认为还需从右往左扫描一遍,记录右上方的点的信息。 实际实现时,只需将整个图左右对称翻转一下即可。

  学习了一下可持久化线段树的正确姿势。

  可持久化线段树的空间一定要开大,开大,开大。

  下图为模拟的小数据可持久化线段树的构造。

参考程序

  1 #include <map>
  2 #include <set>
  3 #include <stack>
  4 #include <queue>
  5 #include <cmath>
  6 #include <ctime>
  7 #include <string>
  8 #include <vector>
  9 #include <cstdio>
 10 #include <cstdlib>
 11 #include <cstring>
 12 #include <cassert>
 13 #include <iostream>
 14 #include <algorithm>
 15 #pragma comment(linker,"/STACK:102400000,102400000")
 16 using namespace std;
 17
 18 #define N 1000008
 19 #define M 50008
 20 #define LL long long
 21 #define lson l,m,rt<<1
 22 #define rson m,r+1,rt<<1|1
 23 #define clr(x,v) memset(x,v,sizeof(x));
 24
 25 const int mo  = 1000000007;
 26 const int inf = 0x3f3f3f3f;
 27 const int INF = 2000000000;
 28 /**************************************************************************/
 29 struct node{
 30     int x,y;
 31     bool operator < (const node &b) const {
 32         return x<b.x || x==b.x && y<b.y;
 33     }
 34     node(int x=0,int y=0):x(x),y(y){}
 35 }a[N];
 36 int n,flag;
 37 map<pair<int,int>,int> Mpp;
 38
 39 int mx[M],my[M];
 40
 41 int cnt;
 42 int sum[N<<3],ls[N<<3],rs[N<<3];
 43 int root[M];
 44
 45 void dfs(int rt,int l,int r){
 46     if (rt==0) return;
 47     printf("%d %d %d %d\n",rt,l,r,sum[rt]);
 48     if (l==r) return;
 49     int m=(l+r)/2;
 50     dfs(ls[rt],l,m);
 51     dfs(rs[rt],m+1,r);
 52 }
 53 void debug(){
 54     printf("====================\n");
 55     dfs(root[0],1,3);
 56     printf("\n");
 57     dfs(root[1],1,3);
 58     printf("\n");
 59     dfs(root[2],1,3);
 60     printf("\n");
 61     dfs(root[3],1,3);
 62     printf("====================\n");
 63 }
 64 void pushup(int rt){
 65     int l=ls[rt],r=rs[rt];
 66     sum[rt]=sum[l]+sum[r];
 67 }
 68 void build(int &rt,int l,int r){
 69     rt=++cnt;
 70     sum[rt]=0;
 71     if (l==r) return;
 72     int m=(l+r)/2;
 73     build(ls[rt],l,m);
 74     build(rs[rt],m+1,r);
 75     pushup(rt);
 76 }
 77 void update(int pos,int val,int x,int &y,int l,int r){
 78     y=++cnt;
 79     if (l==r){
 80         sum[y]=sum[x]+val;
 81         return;
 82     }
 83     ls[y]=ls[x]; rs[y]=rs[x];
 84     int m=(l+r)/2;
 85     if (pos <= m) update(pos,val,ls[x],ls[y],l,m);
 86     if (m  < pos) update(pos,val,rs[x],rs[y],m+1,r);
 87     pushup(y);
 88 }
 89
 90 int query(int L,int R,int rt,int l,int r){
 91     if (L<=l && r<=R){
 92         return sum[rt];
 93     }
 94     int m=(l+r)/2;
 95     int res=0;
 96     if (L <= m) res+=query(L,R,ls[rt],l,m);
 97     if (m <  R) res+=query(L,R,rs[rt],m+1,r);
 98     return res;
 99 }
100
101 void work1(){
102     clr(mx,0); clr(my,0);
103     cnt=0;
104     build(root[0],1,50000);
105     int last=root[0];
106     for (int i=1;i<=n;i++){
107         int x1=a[i].x , y1=a[i].y;
108         int x2=a[my[y1]].x , y2=a[mx[x1]].y;
109         update(y1,1,last,root[x1],1,50000);
110         int k1=query(y2+1,y1,root[x1],1,50000);
111         int k2=query(y2+1,y1,root[x2],1,50000);
112         if (k1!=k2+1) { flag=0; return; }
113         mx[a[i].x]=i; my[a[i].y]=i; last=root[x1];
114     }
115 }
116
117 int main(){
118     int T;
119     while (~scanf("%d",&n)){
120         if (n==0) break;
121          Mpp.clear();
122         int num=0;
123         for (int i=1;i<=n;i++){
124             int x,y;
125             scanf("%d %d",&x,&y);
126             if (Mpp[make_pair(x,y)]==1){
127                 num++;
128             }
129             else
130             {
131                 Mpp[make_pair(x,y)]=1;
132                 a[i-num].x=x;
133                 a[i-num].y=y;
134             }
135         }
136         n=n-num;
137         sort(a+1,a+n+1);
138         flag=1;
139         work1();
140         for (int i=1;i<=n;i++) a[i].x=50001-a[i].x;
141         sort(a+1,a+n+1);
142         work1();
143         printf("%s\n",flag ? "YES" : "NO" );
144     }
145 }
146 /*
147 5
148 1 1
149 1 2
150 1 3
151 2 1
152 3 3
153 */

时间: 2024-10-24 12:02:33

HDU 5820 (可持久化线段树)的相关文章

hdu 2665 可持久化线段树求区间第K大值(函数式线段树||主席树)

http://acm.hdu.edu.cn/showproblem.php?pid=2665 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first line is the number of the test cases. For each test case, the first line contain two integer n and m (

HDU 4866 Shooting(持久化线段树)

view code//第二道持久化线段树,照着别人的代码慢慢敲,还是有点不理解 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; typedef long long ll; #define lson l,m,ls[rt] #define rson m+1,r,rs[r

归并树 划分树 可持久化线段树(主席树) 入门题 hdu 2665

如果题目给出1e5的数据范围,,以前只会用n*log(n)的方法去想 今天学了一下两三种n*n*log(n)的数据结构 他们就是大名鼎鼎的 归并树 划分树 主席树,,,, 首先来说两个问题,,区间第k大 ,,,, 这个问题的通用算法是 划分树,, 说白一点就是把快速排序的中间结果存起来, 举个栗子 原数列 4 1 8 2 6 9 5 3 7 sorted 1 2 3 4 5 6 7 8 9 ........................... qs[0] 4 1 8 2 6 9 5 3 7 q

HDU 2665 Kth number 可持久化线段树

题意:给n个数和m个询问,询问l,r,k是从l~r中的第k小 思路:可持久化线段树的模板题 说下自己对可持久化线段树的理解吧 可持久化线段树的是可以保存历史版本的线段树,就是插进去第i个数的线段树的状态,这样我们可以通过state[r]-state[l-1]来得到state[l~r] 朴素做法就是维护n颗线段树,但是这样一般都会MLE 可持久化线段树利用了每次插入数只修改了线段树上一条链的特性来每次插入一个数只新建一条链来维护历史版本,空间复杂度O(n*logn+n*logn) 原树+新建的链

HDU 4417.Super Mario-无修改区间小于等于H的数的个数-可持久化线段树

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 9618    Accepted Submission(s): 4074 Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability

学习笔记:可持久化线段树

1.前言 线段树,众所周知,在树中的每一个元素中,保存的是线段中的一段,所维护的内容或是最大最小值,或是和等等.可持久化线段树,属于可持久化数据结构中的一种,对于可持久化数据结构这个大知识,我暂时没有去研究,今天只讲其冰山一角. 2.概念 先讲”可持久化“的含义.”可持久化“表示我们当前在处理每个状态,而之前的状态即状态的历史版本全部能够存下来.可持久化线段树,实质上是多颗线段树,最简单的可持久化线段树的题目:求区间第k大.显而易见,求区间最大值的时候我们用普通的线段树就行了,第k大总不能一个个

主席树/函数式线段树/可持久化线段树

什么是主席树 可持久化数据结构(Persistent data structure)就是利用函数式编程的思想使其支持询问历史版本.同时充分利用它们之间的共同数据来减少时间和空间消耗. 因此可持久化线段树也叫函数式线段树又叫主席树. 可持久化数据结构 在算法执行的过程中,会发现在更新一个动态集合时,需要维护其过去的版本.这样的集合称为是可持久的. 实现持久集合的一种方法时每当该集合被修改时,就将其整个的复制下来,但是这种方法会降低执行速度并占用过多的空间. 考虑一个持久集合S. 如图所示,对集合的

主席树 | | 可持久化线段树

可持久化数据结构(Persistent data structure)就是利用函数式编程的思想使其支持询问历史版本.同时充分利用它们之间的共同数据来减少时间和空间消耗. 所以这里讲的可持久化线段树也叫函数式线段树(又叫主席树……因为先驱就是fotile主席Orz……). 先了解一下主席树 http://seter.is-programmer.com/posts/31907.html    很详细的介绍了函数式线段树(主席树). 主席树其实就是很多棵线段树,由于每次更新只需要更新logN个节点,所

HDU 4902 Nice boat(线段树)

HDU Nice boat 题目链接 题意:给定一个序列,两种操作,把一段变成x,把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 思路:线段树,每个结点多一个cover表示该位置以下区间是否数字全相同,然后每次延迟操作,最后输出的时候单点查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1