HDU 4417 Super Mario(2012杭州网络赛 H 离线线段树)
突然想到的节约时间的方法,感觉6翻了
给你n个数字,接着m个询问。每次问你一段区间内不大于某个数字(不一定是给你的数字)的个数
直接线段树没法做,因为每次给你的数字不一样,父节点无法统计。但是离线一下,如果后面的询问可以用前面已经处理过的一些东西,则可以节约时间。换句话说,就是直接把给数字z进行从小到大排序,每次暴力更新数字a小于等于数字z的叶子节点,数字a赋值为极大值,这样前面更新了的数字a在后面就不需要再更新了,而且后面的数字z一定不小于前面更新了的数字a,而且总数一共最多更新n次
做了这么一些线段树有一些心得就是:有时看似区间内部复杂得无法统计的东西,其实从叶子节点开始,两个两个合并在一起就可以解决的话,则只需要每次处理上下更新就可以处理整棵树了,但是注意这儿有孩子节点只影响父亲节点这个条件
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #include<string> #include<cstdio> #include<cstring> #include<stdlib.h> #include<iostream> #include<algorithm> using namespace std; #define eps 1E-8 /*注意可能会有输出-0.000*/ #define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型 #define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化 #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0 #define mul(a,b) (a<<b) #define dir(a,b) (a>>b) typedef long long ll; typedef unsigned long long ull; const int Inf=1<<30; const double Pi=acos(-1.0); const int Max=100010<<2; const int Mod=10; struct node { int minx,sum;//区间最小值 区间-1的个数(-1代表叶子没有这个值) }segtr[Max]; struct nide { int lef,rig,hei,pos; }qes[Max]; int nmin(int a,int b) { return a>b?b:a; } void Upnow(int now,int next) { segtr[now].sum=segtr[next].sum+segtr[next|1].sum; segtr[now].minx=nmin(segtr[next].minx,segtr[next|1].minx); return; } void Create(int sta,int enn,int now) { if(sta==enn) { segtr[now].sum=0; scanf("%d",&segtr[now].minx); return; } int mid=dir(sta+enn,1); int next=mul(now,1); Create(sta,mid,next); Create(mid+1,enn,next|1); Upnow(now,next); return; } bool cmp(struct nide p1,struct nide p2) { return p1.hei<p2.hei;//关键 从小到大 } int ans[Max]; int Query(int sta,int enn,int now,int x,int y,int z) { if(sta>=x&&enn<=y) { if(segtr[now].minx>z)//此区间没有值大于z return segtr[now].sum;//注意这儿之前删除的叶子一定是大于等于z的(排序的原因) else if(sta==enn)//是叶子就更新回溯,不是的话就继续递归下去 { segtr[now].minx=Inf;//赋值为极大值,则一定不z大 segtr[now].sum=1; return 1; } } int mid=dir(sta+enn,1); int next=mul(now,1); int ans=0; if(mid>=x) ans+=Query(sta,mid,next,x,y,z); if(mid<y) ans+=Query(mid+1,enn,next|1,x,y,z); Upnow(now,next); return ans; } int main() { int t,n,q,coun=0; scanf("%d",&t); while(t--) { scanf("%d %d",&n,&q); Create(1,n,1); for(int i=0;i<q;i++) { scanf("%d %d %d",&qes[i].lef,&qes[i].rig,&qes[i].hei); qes[i].pos=i; qes[i].lef++,qes[i].rig++; } sort(qes,qes+q,cmp);//按照hei从小到大,前面的更新了线段树,后面就可以继续用 for(int i=0;i<q;i++) ans[qes[i].pos]=Query(1,n,1,qes[i].lef,qes[i].rig,qes[i].hei);//离线统计 printf("Case %d:\n",++coun); for(int i=0;i<q;i++) printf("%d\n",ans[i]); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决