LUOGU P4088 [USACO18FEB]Slingshot(线段树)
解题思路
推了推式子发现是个二维数点,想了想似乎排序加线段树难写,就写了个树套树,结果写完看见空间才\(128M\)。。各种奇技淫巧卡空间还是\(MLE\)到天上。后来只好乖乖的写排序+线段树。做法就是把式子写出来,然后把绝对值分类讨论成四种情况,发现这就是二维数点,然后讨论每种情况排序算最小值。
代码1(树套树 30pts)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=200005;
const int M=N*20;
inline int rd(){
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return f?x:-x;
}
int n,m,xx[N<<2],yy[N<<2],tt[N],cnt,u,tot,cpy[N<<2],rt,num;
LL ans=1e18;
struct Segment_Tree_in{
int rt[N<<2],ls[M],rs[M];
LL Min[M];
inline void init(){
memset(Min,0x3f,sizeof(Min));
}
void update(int &x,int l,int r,int pos,LL w){
if(!x) x=++tot; Min[x]=min(Min[x],w);
if(l==r) return; int mid=(l+r)>>1;
if(pos<=mid) update(ls[x],l,mid,pos,w);
else update(rs[x],mid+1,r,pos,w);
}
LL query(int x,int l,int r,int L,int R){
if(!x) return 1e18;
if(L<=l && r<=R) return Min[x];
int mid=(l+r)>>1; LL ret=1e18;
if(L<=mid) ret=min(ret,query(ls[x],l,mid,L,R));
if(mid<R) ret=min(ret,query(rs[x],mid+1,r,L,R));
return ret;
}
}tree2[2];
struct Segment_Tree_out{
int ls[N<<2],rs[N<<2];
void update(int &x,int l,int r,int i,int op){
if(!x) x=++num;
tree2[0].update(tree2[0].rt[x],1,u,yy[i],1ll*cpy[xx[i]]*op+cpy[yy[i]]+tt[i]);
tree2[1].update(tree2[1].rt[x],1,u,yy[i],1ll*cpy[xx[i]]*op-cpy[yy[i]]+tt[i]);
if(l==r) return; int mid=(l+r)>>1;
if(xx[i]<=mid) update(ls[x],l,mid,i,op);
else update(rs[x],mid+1,r,i,op);
}
LL query(int x,int l,int r,int x1,int x2,int y1,int y2,int op){
if(!x) return 1e18;
if(x1<=l && r<=x2) return tree2[op].query(tree2[op].rt[x],1,u,y1,y2);
int mid=(l+r)>>1; LL ret=1e18;
if(x1<=mid) ret=min(ret,query(ls[x],l,mid,x1,x2,y1,y2,op));
if(mid<x2) ret=min(ret,query(rs[x],mid+1,r,x1,x2,y1,y2,op));
return ret;
}
}tree1[2];
//0+ 1-
int main(){
tree2[0].init(); tree2[1].init();
n=rd(),m=rd(); int x,y,t,X,Y;
for(int i=1;i<=n;i++){
x=rd(),y=rd(),t=rd();
xx[i]=x; yy[i]=y; tt[i]=t;
cpy[++cnt]=x; cpy[++cnt]=y;
}
for(int i=1;i<=m;i++){
x=rd(),y=rd();
cpy[++cnt]=x; cpy[++cnt]=y;
xx[i+n]=x; yy[i+n]=y;
}
sort(cpy+1,cpy+1+cnt);
u=unique(cpy+1,cpy+1+cnt)-cpy-1;
for(int i=1;i<=n;i++){
xx[i]=lower_bound(cpy+1,cpy+1+u,xx[i])-cpy;
yy[i]=lower_bound(cpy+1,cpy+1+u,yy[i])-cpy;
tree1[0].update(rt,1,u,i,1);
tree1[1].update(rt,1,u,i,-1);
}
for(int i=1;i<=m;i++){
x=lower_bound(cpy+1,cpy+1+u,xx[i+n])-cpy;
y=lower_bound(cpy+1,cpy+1+u,yy[i+n])-cpy;
ans=abs(cpy[x]-cpy[y]);
ans=min(ans,tree1[0].query(1,1,u,x+1,u,y+1,u,0)-cpy[x]-cpy[y]);
ans=min(ans,tree1[0].query(1,1,u,x+1,u,1,y,1)-cpy[x]+cpy[y]);
ans=min(ans,tree1[1].query(1,1,u,1,x,y+1,u,0)+cpy[x]-cpy[y]);
ans=min(ans,tree1[1].query(1,1,u,1,x,1,y,1)+cpy[x]+cpy[y]);
printf("%lld\n",ans);
}
return 0;
}
代码2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=400005;
inline int rd(){
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return f?x:-x;
}
int n,m,xx[N<<2],yy[N<<2],tt[N],cnt,u,cpy[N<<2];
LL ans[N];
struct Segment_Tree{
LL Min[N<<2];
inline void init(){
memset(Min,0x3f,sizeof(Min));
}
void update(int x,int l,int r,int pos,LL w){
Min[x]=min(Min[x],w);
if(l==r) return; int mid=(l+r)>>1;
if(pos<=mid) update(x<<1,l,mid,pos,w);
else update(x<<1|1,mid+1,r,pos,w);
}
LL query(int x,int l,int r,int L,int R){
if(L<=l && r<=R) return Min[x];
int mid=(l+r)>>1; LL ret=1e18;
if(L<=mid) ret=min(ret,query(x<<1,l,mid,L,R));
if(mid<R) ret=min(ret,query(x<<1|1,mid+1,r,L,R));
return ret;
}
}tree;
struct Node{
int x,y,t,op,id;
Node(int _x=0,int _y=0,int _t=0,int _op=0,int _id=0){
x=_x; y=_y; t=_t; op=_op; id=_id;
}
}node[N];
inline bool cmp1(Node A,Node B){
return (A.x==B.x)?A.y<B.y:A.x<B.x;
}
inline bool cmp2(Node A,Node B){
return (A.x==B.x)?A.y>B.y:A.x<B.x;
}
inline bool cmp3(Node A,Node B){
return (A.x==B.x)?A.y<B.y:A.x>B.x;
}
inline bool cmp4(Node A,Node B){
return (A.x==B.x)?A.y>B.y:A.x>B.x;
}
int main(){
n=rd(),m=rd(); int x,y,t,pos;
for(int i=1;i<=n;i++){
x=rd(),y=rd(),t=rd();
xx[i]=x; yy[i]=y; tt[i]=t;
cpy[++cnt]=x; cpy[++cnt]=y;
}
for(int i=1;i<=m;i++){
x=rd(),y=rd(); ans[i]=abs(x-y);
cpy[++cnt]=x; cpy[++cnt]=y;
xx[i+n]=x; yy[i+n]=y;
}
sort(cpy+1,cpy+1+cnt);
u=unique(cpy+1,cpy+1+cnt)-cpy-1;
for(int i=1;i<=n;i++) {
xx[i]=lower_bound(cpy+1,cpy+1+u,xx[i])-cpy;
yy[i]=lower_bound(cpy+1,cpy+1+u,yy[i])-cpy;
node[i]=Node(xx[i],yy[i],tt[i],0,0);
}
for(int i=1;i<=m;i++){
x=lower_bound(cpy+1,cpy+1+u,xx[i+n])-cpy;
y=lower_bound(cpy+1,cpy+1+u,yy[i+n])-cpy;
node[i+n]=Node(x,y,0,1,i);
}
tree.init();
sort(node+1,node+1+n+m,cmp1);
for(int i=1;i<=n+m;i++){
x=node[i].x,y=node[i].y;
if(!node[i].op) tree.update(1,1,u,y,-cpy[x]-cpy[y]+node[i].t);
else ans[node[i].id]=min(ans[node[i].id],tree.query(1,1,u,1,y)+cpy[x]+cpy[y]);
}
tree.init();
sort(node+1,node+1+n+m,cmp2);
for(int i=1;i<=n+m;i++){
x=node[i].x,y=node[i].y;
if(!node[i].op) tree.update(1,1,u,y,-cpy[x]+cpy[y]+node[i].t);
else ans[node[i].id]=min(ans[node[i].id],tree.query(1,1,u,y+1,u)+cpy[x]-cpy[y]);
}
tree.init();
sort(node+1,node+1+n+m,cmp3);
for(int i=1;i<=n+m;i++){
x=node[i].x,y=node[i].y;
if(!node[i].op) tree.update(1,1,u,y,cpy[x]-cpy[y]+node[i].t);
else ans[node[i].id]=min(ans[node[i].id],tree.query(1,1,u,1,y)-cpy[x]+cpy[y]);
}
tree.init();
sort(node+1,node+1+n+m,cmp4);
for(int i=1;i<=n+m;i++){
x=node[i].x,y=node[i].y;
if(!node[i].op) tree.update(1,1,u,y,cpy[x]+cpy[y]+node[i].t);
else ans[node[i].id]=min(ans[node[i].id],tree.query(1,1,u,y+1,u)-cpy[x]-cpy[y]);
}
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}
LUOGU P4088 [USACO18FEB]Slingshot(线段树)的更多相关文章
- P4088 [USACO18FEB]Slingshot 线段树+扫描线
\(\color{#0066ff}{ 题目描述 }\) Farmer John最讨厌的农活是运输牛粪.为了精简这个过程,他产生了一个新奇的想法:与其使用拖拉机拖着装满牛粪的大车从一个地点到另一个地点, ...
- NOIP 2016 天天爱跑步 (luogu 1600 & uoj 261) - 线段树
题目传送门 传送点I 传送点II 题目大意 (此题目不需要大意,我认为它已经很简洁了) 显然线段树合并(我也不知道哪来这么多显然) 考虑将每条路径拆成两条路径 s -> lca 和 t -> ...
- [Luogu P4215] 踩气球 (线段树)
题面 传送门:https://www.luogu.org/problemnew/show/P4215 Solution 这题十分有意思. 首先,我们可以先想想离线做法,因为在线做法可以从离线做法推出. ...
- 洛谷P4088 [USACO18FEB]Slingshot
题面 大意:给出n个弹弓,可以用ti的时间把xi位置运到yi,在给出m组询问,求xj到yj最小时间. sol:首先如果不用弹弓,时间应为abs(xj-yj).否则时间就是abs(xi-xj)+abs( ...
- luogu P4198 楼房重建——线段树
题目大意: 小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段表示,其中Hi为第i栋楼房的高度.如果这栋楼房上任何一个高度大于0的点与(0,0)的连线没有与之前的线 ...
- Luogu 3369 我用线段树骗了一道平衡树题……
这篇博客毫无意义-- 只是表达一下我仍然会写树状数组和线段树-- 题目链接 #include <cstdio> #include <cstring> #include < ...
- [Luogu P4198]楼房重建(线段树)
题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些事件发生在一个 ...
- [ Luogu 3924 ] 康纳的线段树
\(\\\) \(Description\) 现在有一个线段树维护长为\(N\)的数列,实现方式是\(mid=((l+r)>>1)\),支持区间加,节点维护区间和. 共有\(M\)次区间加 ...
- luogu P3765 总统选举(线段树维护摩尔投票+平衡树)
这题需要一个黑科技--摩尔投票.这是一个什么东西?一个神奇的方法求一个序列中出现次数大于长度一半的数. 简而言之就是同加异减: 比如有一个代表投票结果的序列. \[[1,2,1,1,2,1,1]\] ...
随机推荐
- 【ABAP系列】SAP ABAP模块-取整操作中CEIL和FLOOR用法
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP模块-取整操作中 ...
- Convolutional Neural Networks(3):Convolution and Channels
在CNN(1)和CNN(2)两篇文章中,主要说明的是CNN的基本架构和权值共享(Weight Sharing),本文则重点介绍卷积的部分. 首先,在卷积之前,我们的数据是4D的tensor(width ...
- IIS网站绑定域名
你新建的网站右键-->编辑绑定-->添加 -->类型:http,IP地址:全部未分配,端口号:80,主机名:你的域名,例如yangche.cn-->确定
- 排序算法五:随机化快速排序(Randomized quicksort)
上一篇提到,快速排序的平均时间复杂度是O(nlgn),比其他相同时间复杂度的堆排序.归并排序都要快,但这是有前提的,就是假定要排序的序列是随机分布的,而不是有序的.实际上,对于已经排好的序列,如果用快 ...
- Docker 换源
近几天又折腾起 docker来了 我发现自己在拉镜像的时候,总是超时 然后百度了一下 说要换源 90sec的一个水友 推荐了我 阿里云的加速源 我看了还是免费就想试一下 讲一下过程 ...
- servlet--三大域
requset \ session servletContext application
- ELK日志分析系统之logstash7.x最新版安装与配置
2 .Logstash的简介 2.1 logstash 介绍 LogStash由JRuby语言编写,基于消息(message-based)的简单架构,并运行在Java虚拟机(JVM)上.不同于分离的代 ...
- jvm(1)性能监控-linux相关命令
top命令能够实时显示系统中各个进程的资源占用情况,其输出信息分为两部分,前半部分为系统统计信息,后半部分是进程信息. 第一行是任务队列信息,它的结果等同于uptime命令. 第二行是进程统计信息: ...
- Page.IsPostBack
ASP.NET页面的执行顺序说明:Page_Init(页面初始化引发的事件)——Page_Load(加载页面时引发的事件)——ControlEvent(服务器控件引发的事件)——Page_UnLoad ...
- 让 Git Bisect 帮助你
让 Git Bisect 帮助你 英文原文:Letting Git Bisect Help You Git 提供来很多的工具来帮助我们改进工作流程. bisect 命令就是其中之一, 虽然由于使用 ...