【CF 474E】Pillars
2015-08-17 00:51
309 查看
【CF 474E】Pillars
离散化+线段树dp
大半夜写出来了。。。好长好长好长好长好挫……先把高度排序离散化 我又开了个哈希数组用来查某点对应离散后的点 然后遍历每个点时二分出满足题意的区间(1~h-d)(h+d~max) 然后线段树查两个区间当前最大长度的序列 累计到当前点对应的树内点 同时更新他的父亲点们的最大长度 再把之前最大长度的末尾作为当前点的前驱 如果没有就用当前点自己做前驱 最后输出树根存的节点的前驱们(即为树内最长的序列) 各种节点哈希的有点混乱……代码……看乱了就别看了= =我现在看的都有点乱
代码如下:
离散化+线段树dp
大半夜写出来了。。。好长好长好长好长好挫……先把高度排序离散化 我又开了个哈希数组用来查某点对应离散后的点 然后遍历每个点时二分出满足题意的区间(1~h-d)(h+d~max) 然后线段树查两个区间当前最大长度的序列 累计到当前点对应的树内点 同时更新他的父亲点们的最大长度 再把之前最大长度的末尾作为当前点的前驱 如果没有就用当前点自己做前驱 最后输出树根存的节点的前驱们(即为树内最长的序列) 各种节点哈希的有点混乱……代码……看乱了就别看了= =我现在看的都有点乱
代码如下:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define LL long long #define sz 100000 #define sr "%lld" using namespace std; typedef struct Hash//离散化后哈希用 { LL h;//当前点高度 int id;//离散前节点号 bool operator < (const struct Hash a)const { return h < a.h; } }Hash; typedef struct Node//线段树 { int len,Maxid,id; }Node; Node lt[sz*4+100];//线段树 Hash hs[sz+2];//离散 int to[sz+2];//记录某点离散后对应点序号 int pre[sz+2];//前驱 int n; void ReBuild(int site,int l,int r)//初始化线段树 { if(l == r)//叶子节点初始长度0 节点号为离散后标号 最大序列节点为自己 { lt[site].len = 0; lt[site].Maxid = site; lt[site].id = l; return; } int m = (l+r)>>1; ReBuild(site<<1,l,m); ReBuild(site<<1|1,m+1,r); lt[site].len = lt[site].Maxid = 0;//树内节点长度 最大序列节点初始0 } int LowerBound(LL x)//二分查<= h-d的最大下标 { int l = 1,r = n,mid,ans = 0; while(l <= r) { mid = (l+r)>>1; if(hs[mid].h <= x) { ans = mid; l = mid+1; }else r = mid-1; } return ans; } int UpperBound(LL x)//二分查>= h+d的最小下标 { int l = 1,r = n,mid,ans = 0; while(l <= r) { mid = (l+r)>>1; if(hs[mid].h >= x) { ans = mid; r = mid-1; }else l = mid+1; } return ans; } int Find(int site,int l,int r,int ll,int rr)//找当前点前的最长序列 { if(l == ll && r == rr) { return lt[site].Maxid;//返回当前结点最长序列下标 } int mid = (l+r)>>1; int a,b; if(mid >= rr) return Find(site<<1,l,mid,ll,rr); else if(mid < ll) return Find(site<<1|1,mid+1,r,ll,rr); else { a = Find(site<<1,l,mid,ll,mid); b = Find(site<<1|1,mid+1,r,mid+1,rr); if(lt[a].len > lt[b].len) return a; else return b; } } void Updata(int site,int l,int r,int id,int mid)//更新树内当前点之前最长序列 { if(l == r && l == id) { lt[site].len = lt[mid].len+1; if(mid)//没有更新当前点前驱为自己 { pre[hs[id].id] = hs[lt[mid].id].id; }else pre[hs[id].id] = hs[id].id;//否则为最长序列末端 return; } int md = (l+r)>>1; if(md >= id) { Updata(site<<1,l,md,id,mid); if(lt[site].len < lt[site<<1].len) { lt[site].Maxid = lt[site<<1].Maxid; lt[site].len = lt[site<<1].len; } } else { Updata(site<<1|1,md+1,r,id,mid); if(lt[site].len < lt[site<<1|1].len) { lt[site].Maxid = lt[site<<1|1].Maxid; lt[site].len = lt[site<<1|1].len; } } } void Print(int x)//递归输出最长序列 { if(x == pre[x]) { printf("%d",x); return; } Print(pre[x]); printf(" %d",x); } int main() { int d,i,x1,x2,l; scanf("%d %d",&n,&d); for(i = 1; i <= n; ++i)//建立哈希数组 { scanf(sr,&hs[i].h); hs[i].id = i; } if(d == 0)//特判距离0直接1~n输出 { printf("%d\n",n); for(i = 1; i < n; ++i) printf("%d ",i); printf("%d\n",n); return 0; } sort(hs+1,hs+1+n);//按高度对哈希数组排序 for(i = 1; i <= n; ++i)//安插哈希节点 { to[hs[i].id] = i; } ReBuild(1,1,n);//建树 lt[0].len = lt[0].Maxid = 0; for(i = 1; i <= n; ++i) { l = LowerBound(hs[to[i]].h-d);//二分找h-d if(l) x1 = Find(1,1,n,1,l);//找到则查到最长序列 else x1 = 0; l = UpperBound(hs[to[i]].h+d);//二分找h+d if(l) x2 = Find(1,1,n,l,n); else x2 = 0; if(lt[x1].len > lt[x2].len) Updata(1,1,n,to[i],x1);//用最长序列更新树内当前结点 else Updata(1,1,n,to[i],x2); } printf("%d\n",lt[1].len); Print(hs[lt[lt[1].Maxid].id].id); puts(""); return 0; }
相关文章推荐
- 重温 w3cshool css3
- OC_Notifications(通知)
- hdoj5253
- leetcode 130: Surrounded Regions
- C语言中的dirent.h说明
- /sys/class/gpio 文件接口操作IO端口(s3c2440)
- TYVJ 1330 乳草的入侵
- CSS3属性box-flex
- 编写高质量代码改善C#程序的157个建议——建议55:利用定制特性减少可序列化的字段
- Oracle清理回收站的方法
- IO流笔记01
- R语言抓取pm2.5数据绘制全国pm2.5分布图
- Oracle清理回收站的方法
- ListView的工作原理及优化
- sublime text 3 快捷键大全以及配置编译环境
- Linux学习笔记:系统启动引导过程
- HDU_1176_免费馅饼
- QQ安装教程 2 -for wuqs
- QQ安装教程 2 -for wuqs
- 计算机基本常识