博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU6089 恐怖分子(变形线段树)
阅读量:5127 次
发布时间:2019-06-13

本文共 2887 字,大约阅读时间需要 9 分钟。

题目描述

n*m的平面内有K个不安全点,Q个询问位置在(x,y)的人能走到多少个点?从(x,y)走到(x',y')是合法的,当且仅当(x,y)和(x',y')之间的矩形中不包含不安全点。

题解

问题相当于平面中有若干障碍点,询问以某一个点为四个角之一的不包含障碍点的矩形有多少个。

我们只需要考虑一个方向,接下来把整个图旋转90度再算即可 

那一个方向怎么求呢?

正难则反,我们可以考虑逆向思考

如图,线与线交点表示一个坐标,黑点表示不安全点,白点表示询问点

白点右下方可以走到的点数=蓝线内的点数-阴影内的点数

那阴影到底是什么呢?

它其实就是 每一高度的最右边的黑点向下作垂线,与坐标轴围成的最大区域

换句话说,它满足 如果上方的右边界在下方的原右边界右边, 则下方的右边界按上方的算

那我们可以以高度划定区间建一颗线段树,做一些特殊处理就可以求出阴影了
 
原谅我表达能力有限,具体看代码吧
//正难则反 #include
#define mid ((l+r)>>1)using namespace std;const int N=100005;typedef long long ll;int n,m,K,Q,T_Max[N<<2],tot,Max;//T_Max表y在某一区间内的x的最大值ll ans[N],T_sum[N<<2],T_suml[N<<2];struct node { int x,y,id,pd; node() {} node(int a,int b,int c,int d) { x=a;y=b;id=c;pd=d; }}a[N*2],tr[N],q[N];bool cmp(const node &A,const node &B){ return A.x
'9'){
if(ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); return x*f;}ll query_sum(int u,int l,int r,int a,int b,int &mx){ if (a<=l&&r<=b){ if(mx>=T_Max[u]) return (ll)mx*(r-l+1); if(l==r) return mx=T_Max[u]; int tt=T_Max[u<<1|1]; ll res=0; if(mx>=tt){
//即T_Max[u<<1|1]<=mx
<<1] res+=(ll)mx*(r-mid); res+=query_sum(u<<1,l,mid,a,b,mx); }else{
//即mx
<<1|1](T_Max[u<<1]的范围不限) res+=T_suml[u]; res+=query_sum(u<<1|1,mid+1,r,a,b,mx); } mx=T_Max[u]; return res; } ll s=0; if(b>mid) s+=query_sum(u<<1|1,mid+1,r,a,b,mx);//先更新上边以更新右边界 if(a<=mid) s+=query_sum(u<<1,l,mid,a,b,mx); return s;}void ins(int u,int l,int r,int y,int x){ if(l==r){ if(x>T_Max[u]) T_Max[u]=T_sum[u]=x; return; } if(y<=mid) ins(u<<1,l,mid,y,x); else ins(u<<1|1,mid+1,r,y,x); int tt=T_Max[u<<1|1]; T_suml[u]=query_sum(u<<1,l,mid,l,mid,tt);//注意直接写T_max[u<<1|1]的话可能会被修改 T_Max[u]=max(T_Max[u<<1],T_Max[u<<1|1]); T_sum[u]=T_suml[u]+T_sum[u<<1|1]; //如果T_max[u<<1|1]>[l,mid]区间的原右边界,则[l,mid]区间的右边界按T_max[u<<1|1]算 //否则,按原右边界算}void calc(){ tot=0; for (int i=1;i<=K;i++) a[++tot]=node(tr[i].x,tr[i].y,i,0); for (int i=1;i<=Q;i++) a[++tot]=node(q[i].x,q[i].y,i,1); sort(a+1,a+tot+1,cmp); for (int i=1;i<=tot;i++){ if(!a[i].pd) ins(1,1,m,a[i].y,a[i].x); else{ Max=0;ans[a[i].id]+=query_sum(1,1,m,1,a[i].y,Max);//二维数点 Max=0;ans[a[i].id]-=query_sum(1,1,m,a[i].y,a[i].y,Max);//减去重复的同行/同列轴 } }}int main(){ n=read();m=read();K=read();Q=read(); for (int i=1;i<=K;i++) tr[i].x=read(),tr[i].y=read(); for (int i=1;i<=Q;i++) q[i].x=read(),q[i].y=read(),ans[i]=0; for (int i=0;i<4;i++){ calc(); for (int i=1;i<=(m<<2); i++) T_sum[i]=T_suml[i]=T_Max[i]=0;//清零 for (int j=1;j<=K;j++) tr[j].x=n-tr[j].x+1,swap(tr[j].x,tr[j].y);//旋转90度 for (int j=1;j<=Q;j++) q[j].x=n-q[j].x+1,swap(q[j].x,q[j].y); swap(n,m); } for (int i=1;i<=Q;i++) printf("%lld\n",(ll)n*m-ans[i]); return 0;}

转载于:https://www.cnblogs.com/HarryPotter-fan/p/11317080.html

你可能感兴趣的文章
OD使用教程20 - 调试篇20
查看>>
Java虚拟机(JVM)默认字符集详解
查看>>
Java Servlet 过滤器与 springmvc 拦截器的区别?
查看>>
(tmp >> 8) & 0xff;
查看>>
linux命令之ifconfig详细解释
查看>>
NAT地址转换
查看>>
Nhibernate 过长的字符串报错 dehydration property
查看>>
Deque - leetcode 【双端队列】
查看>>
人物角色群体攻击判定(一)
查看>>
一步步学习微软InfoPath2010和SP2010--第九章节--使用SharePoint用户配置文件Web service(2)--在事件注册表单上创建表单加载规则...
查看>>
gulp插件gulp-ruby-sass和livereload插件
查看>>
免费的大数据学习资料,这一份就足够
查看>>
clientWidth、clientHeight、offsetWidth、offsetHeight以及scrollWidth、scrollHeight
查看>>
MySQL(一)
查看>>
企业级应用与互联网应用的区别
查看>>
Vue父子组件间的通信
查看>>
PHPCMS 模板的设置
查看>>
linux-2.6.38 input子系统(用输入子系统实现按键操作)
查看>>
单点登录 之 OAuth
查看>>
Mysql 性能优化20个原则(2)
查看>>