[GXOI/GZOI2019]特技飞行
题目链接 ![https://www.luogu.org/problem/P5302]
思路:这道题可以说是两道题的合并。注意到\(c\)的分数与 \(a\)和\(b\)的分数 无关,也就是说可以分成两部分来计算。首先,对于\(c\)的分数,发现就是判断点是否在正方形内。于是可以将坐标轴旋转45°(坐标\((x,y)\)映射为坐标\((x+y,x-y)\)不理解的可以手玩一下--),然后就可以转化为经典的扫描线问题了。而后,对于a和b的分数对极值的贡献,可以发现这取决于「对向交换」的次数。「对向交换」显然可以每次都进行,因为题目中说:“容易发现,「对向交换」会使它们的航线变为折线,并保持它们在纵坐标上的相对顺序;而「擦身而过」会改变它们在纵坐标上的相对顺序。”满足题意。而什么时候「对向交换」次数最少呢?我们可以将每个起点向其目标终点的原对应起点连一条边(在样例1中,\(1--2,2--4,3--3,4--1\)),在这其中会形成环(样例1中\(1--2--4\)以及\(3\)一个自环),每个环都相对独立。对于每个环,其实相当于一个置换,环内需交换次数为:\(环长-1\),且其为最少。因此最少次数为它们的和:\(n-环个数\)。至此,分析就结束了。
具体实现:对于扫描线的问题,离散化后上树状数组就可以了。对于求环的个数,不用连边,而直接用并查集判断有多少集合即可。至于求交点个数及坐标,我个人是把起点终点坐标撞到\(set\)里面,然后用类似于求逆序对的方法实现的。
注意事项:数组大小要注意。\(n\)与\(k\)不同阶。
代码:
#include<bits/stdc++.h>
#define in read()
using namespace std;
const int N=1e5+5;
const double eps=1e-7;
int n,a,b,c,k,xst,xed,ans1,ans2,cnt,num,cp,tt,anss;
int st[N],ed[N],fa[N];
struct nd{int id,h;}tp[N];
struct pot{double x,y;int x1;}tmp[N*5];
struct seg{double he;int v,l,r;}ct[N<<1];
struct cop{double xx;int e,re;}hh[N*10];
bool operator<(nd x,nd y){return x.h<y.h;}
bool operator<(pot x,pot y){return x.y>y.y;}
bool operator<(seg x,seg y){return x.he>y.he;}
inline bool cmp(cop x,cop y){return x.xx<y.xx;}
inline bool cmp1(cop x,cop y){return x.e<y.e;}
inline int read()
{
int s=0,w=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
return s*w;
}
int fd(int x){return fa[x]==x?x:fa[x]=fd(fa[x]);}
inline pot zg(pot w){return pot{w.x+w.y,w.x-w.y,0};}
set<nd>tqx;
inline pot pt(pot a1,pot b1,pot a2,pot b2)
{
double k1=(1.0*(a1.y-b1.y))/(1.0*(a1.x-b1.x)),b11=a1.y-k1*a1.x;
double k2=(1.0*(a2.y-b2.y))/(1.0*(a2.x-b2.x)),b22=a2.y-k2*a2.x;
if(k1-k2==0) return pot{0,0,0};
double x=(b22-b11)/(k1-k2),y=x*k1+b11;
return pot{x,y,0};
}
inline void pre1()
{
for(int i=1;i<=n;++i)
{
int fx=fd(i),fy=fd(tp[i].id);
if(fx!=fy) fa[fx]=fy;
}
ans1=n;
for(int i=1;i<=n;++i)
if(fd(i)==i) --ans1;
}
inline void pre2()
{
for(int i=1;i<=n;++i)
{
set<nd>::iterator it=tqx.upper_bound((nd){i,ed[i]});
for(;it!=tqx.end();it++)
tmp[++ans2]=pt(pot{1.0*xst,st[i],0},pot{1.0*xed,ed[i],0},pot{1.0*xst,st[it->id],0},pot{1.0*xed,ed[it->id],0});
tqx.insert((nd){i,ed[i]});
}
cnt=ans2;
}
struct Tree{
int c[N*10];
inline int lowbit(int x){return x&(-x);}
inline void upd(int x,int v)
{
while(x<=tt)c[x]+=v,x+=lowbit(x);
}
inline int query(int x)
{
int ans=0;
while(x>0)ans+=c[x],x-=lowbit(x);
return ans;
}
}T;
inline void work()
{
sort(tmp+1,tmp+cnt+1);
sort(ct+1,ct+num+1);
int ret=1;
while(tmp[ret].y>ct[1].he&&ret<=cnt) ++ret;
for(int i=1;i<=num;++i)
{
while(tmp[ret].y>ct[i].he&&ret<=cnt)
anss+=(T.query(tmp[ret++].x1)>0);
T.upd(ct[i].l,ct[i].v);
T.upd(ct[i].r+1,-ct[i].v);
}
ans1+=anss*c,ans2+=anss*c;
if(ans1>ans2) swap(ans1,ans2);
printf("%d %d\n",ans1,ans2);
}
int main()
{
n=in,a=in,b=in,c=in,xst=in,xed=in;
for(int i=1;i<=n;++i) fa[i]=i;
for(int i=1;i<=n;++i) st[i]=in;
for(int i=1;i<=n;++i) ed[i]=in;
for(int i=1;i<=n;++i) tp[i].h=ed[i],tp[i].id=i;
sort(tp+1,tp+n+1);
pre1();pre2();
ans1=ans1*a+(ans2-ans1)*b;ans2*=a;
k=in;
for(int i=1;i<=k;++i)
{
double _x=1.0*read(),_y=1.0*read(),_r=1.0*read();
pot pt11=zg(pot{_x,_y-_r,0}),pt12=zg(pot{_x+_r,_y,0});
pot pt21=zg(pot{_x-_r,_y,0}),pt22=zg(pot{_x,_y+_r,0});
ct[++num].he=pt11.y,ct[num].v=1;
ct[++num].he=pt21.y,ct[num].v=-1;
hh[++cp].xx=pt11.x,hh[cp].e=cp;
hh[++cp].xx=pt12.x,hh[cp].e=cp;
hh[++cp].xx=pt21.x,hh[cp].e=cp;
hh[++cp].xx=pt22.x,hh[cp].e=cp;
}
for(int i=1;i<=cnt;++i) tmp[i]=zg(tmp[i]);
for(int i=1;i<=cnt;++i)
hh[++cp].xx=tmp[i].x,hh[cp].e=cp;
sort(hh+1,hh+cp+1,cmp);
for(int i=1;i<=cp;++i)
hh[i].re=(i==1||(hh[i].xx-hh[i-1].xx>=eps))?++tt:tt;
sort(hh+1,hh+cp+1,cmp1);
int num2=num<<1;
for(int i=1;i<=num2;++i,++i)
{
int pos=i+1>>1;
ct[pos].l=hh[i].re;
ct[pos].r=hh[i+1].re;
}
for(int i=num2+1;i<=cp;++i)
tmp[i-num2].x1=hh[i].re;
work();
return 0;
}
[GXOI/GZOI2019]特技飞行的更多相关文章
- P5302 [GXOI/GZOI2019]特技飞行
题目地址:P5302 [GXOI/GZOI2019]特技飞行 这里是官方题解(by lydrainbowcat) 题意 给 \(10^5\) 条直线,给 \(x = st\) 和 \(x = ed\) ...
- 题解-GXOI/GZOI2019 特技飞行
Problem loj3085 bzoj不放题面差评 题意概要:给出两条竖直直线,再给出 \(n\) 架飞机的初始航线:一条接通这两条直线的线段,保证航线交点不在两条直线上.现要求安排所有飞机在航线相 ...
- luogu P5302 [GXOI/GZOI2019]特技飞行
传送门 强行二合一可还行 首先\(c\)的贡献是不会变的,先考虑求出多少交点被矩形覆盖,交点的话可以按左端点纵坐标从下到上顺序枚举一条线段,然后维护右端点纵坐标的set,把之前处理过线段的右端点放进s ...
- [GX/GZOI2019]特技飞行(扫描线+置换)
感觉是6题中最难的一题,其实这题是一个二合一: 第一问:给定平面上若干点和k个关键点,关键点覆盖一个45°倾斜的正方形范围r,求有多少点被至少一个关键点覆盖.这个可以曼哈顿转切比雪夫距离,然后再扫描线 ...
- GXOI/GZOI2019题解
GXOI/GZOI2019题解 P5300 [GXOI/GZOI2019]与或和 一眼题.. 显然枚举每个二进制位,答案就变成了全1子矩阵数量. 这个xjb推推,单调栈一下就行了. #include& ...
- Loj #3085. 「GXOI / GZOI2019」特技飞行
Loj #3085. 「GXOI / GZOI2019」特技飞行 题目描述 公元 \(9012\) 年,Z 市的航空基地计划举行一场特技飞行表演.表演的场地可以看作一个二维平面直角坐标系,其中横坐标代 ...
- 【LOJ】#3085. 「GXOI / GZOI2019」特技飞行
LOJ#3085. 「GXOI / GZOI2019」特技飞行 这显然是两道题,求\(C\)是一个曼哈顿转切比雪夫后的线段树扫描线 求\(AB\),对向交换最大化和擦身而过最大化一定分别为最大值和最小 ...
- 「GXOI / GZOI2019」简要题解
「GXOI / GZOI2019」简要题解 LOJ#3083. 「GXOI / GZOI2019」与或和 https://loj.ac/problem/3083 题意:求一个矩阵的所有子矩阵的与和 和 ...
- BZOJ2697: 特技飞行
2697: 特技飞行 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 607 Solved: 363[Submit][Status] Descript ...
随机推荐
- PowerBuilder学习笔记之行删除卡死问题
在数据窗口勾选这两个选项后,在删除行数据时会导致系统直接崩溃退出
- Centos 安装PHP-redis扩展
从https://pecl.php.net/package/redis 里面找到自己安装的Redis对应版本的redis 1.获取已经安装的Redis版本扩展我这边安装的是4.0.1版本 wget ...
- java 读取文件流
搬运自速学堂:https://www.sxt.cn/Java_jQuery_in_action/ten-iqtechnology.html JAVA中IO流体系: 四大IO抽象类 ·InputStre ...
- win10+pyspark+pycharm+anaconda单机环境搭建
一.工具准备 1. jdk1.8 2. scala 3. anaconda3 4. spark-2.3.1-bin-hadoop2.7 5. hadoop-2.8.3 6. winutils 7. p ...
- javascript -- 把按钮变成读秒倒计时
$('#btn').click(function(){ //设置按钮倒计时 $(this).addClass('disabled'); //把按钮变灰 $(this).attr('disabled', ...
- 关于/var/log/maillog 时间和系统时间不对应的问题 -- 我出现的是日志时间比系统时间慢12个小时
那么让我们来见证奇迹的时刻吧!! 首先你要看下/etc/localtime的软连接,到哪了 一般就是这块出问题了 检查这里就绝对不会错的 对比图 : 这种情况, 删除/etc/localtime : ...
- J.U.C之读写锁:ReentrantReadWriteLock
此篇博客所有源码均来自JDK 1.8 重入锁ReentrantLock是排他锁,排他锁在同一时刻仅有一个线程可以进行访问,但是在大多数场景下,大部分时间都是提供读服务,而写服务占有的时间较少.然而读服 ...
- stm32 ADXL345传感器
加速度灵敏度轴 沿敏感轴加速时相应输出电压增加 寄存器映射 寄存器定义 0x31-DATA_FORMAT SELF_TEST位:设置为1,自测力应用至传感器,造成输出数据转换.值为0时,禁用自测力 S ...
- Android笔记(二十四) Android中的SeekBar(拖动条)
拖动条和进度条非常相似,只是进度条采用颜色填充来表明进度完成的程度,而拖动条则通过滑块的位置来标识数值——而且拖动条允许用户拖动滑块来改变值,因此拖动条通常用于对系统的某种数值进行调节,比如调节音量等 ...
- C++——Inheritence
一种错误的观念: 子类继承父类,只把父类的公有成员继承下来,私有的不会继承. 事实上无论是如何继承,都会把父类的所有成员继承下来. #include<iostream> using nam ...