城市改造 (city)
城市改造 (city)
题目描述
为了节约当前社会巨大的能源消耗,A 城市发起了新能源改造计划,也就是用太阳能代替旧能源。为了简化题意,可以假设 A 城市在一个二维平面上,平面上从11到nn每一个地方都有一栋高楼,高楼的宽度忽略不计。每栋高楼高度为hihi。城市左右两边分别有一座高度为h0h0和hn+1hn+1的高山。每一天,太阳从右边升起,左边落下。
城市改造总共用了TT时刻。每一时刻都发生一下三件事件中的一个事件:
1. 在第ii栋高楼顶端安装太阳能收集器。太阳能收集器只有在光线照射下才能工作。
2. 由于太阳能收集器有寿命,所以将第ii栋高楼上的太阳能收集器拆除。
3. 询问在一天中某一时刻至某一时刻有多少太阳能收集器始终在工作。
你的任务就是对于每个第33种事件,输出有多少太阳能收集器始终在工作。
注意:
太阳能收集器在光线照射下,当且仅当在这一时刻它之前没有遮挡物(包括高楼最高点)。如图,若太阳在下午以45°角照射 A 城,此时图中点2,32,3是不工作的,点1,41,4是工作的。
为了方便确定一天中的时刻,我们将以太阳高度角的形式给出。对于上午,我们给出太阳高度角,而下午,则给出太阳高度角的补角。
输入
第一行,两个数nn和TT。
第二行,输入n+2n+2个整数,第ii个数表示hi−1hi−1。
接下来TT行,每行2∼32∼3个整数。如果第一个数为11,则第二个数表示在第ii栋高楼顶端安装太阳能收集器。如果第一个数为22,则第二个数表示将第ii栋高楼上的太阳能收集器拆除。如果第一个数为33,则输入两个数ta,tbta,tb,表示起始时刻与终止时刻的太阳高度角。
输出
对于每个询问,输出有多少太阳能收集器始终在工作。
样例输入
4 10
5 4 2 6 5 3
1 1
1 3
3 135 135
1 2
3 90 100
1 4
2 3
3 45 50
3 46 50
3 85 95
样例输出
1
3
1
2
3
提示
【样例输入输出 2】
见下放文件 city/city2.in 和 city/city2.ans。这部分样例与第 4 个测试点范围相同。
【样例输入输出 3】
见下放文件 city/city3.in 和 city/city3.ans。这部分样例与第 7 个测试点范围相同。
【样例输出输出 4】
见下放文件 city/city4.in 和 city/city4.ans。这部分样例与第 14 个测试点范围相同。
【样例输出输出 5】
见下放文件 city/city5.in 和 city/city5.ans。这部分样例与第 17 个测试点范围相同。
【子任务】
测试点编号 |
n |
T |
特殊性质 |
1 |
≤105≤105 |
=1=1 |
无 |
2 |
≤100≤100 |
≤100≤100 |
|
3 |
|||
4 |
≤1000≤1000 |
≤1000≤1000 |
|
5 |
|||
6 |
|||
7 |
≤105≤105 |
≤10≤10 |
|
8 |
|||
9 |
|||
10 |
≤105≤105 |
除h0h0和hn+1hn+1,所有的hihi都相等 |
|
11 |
|||
12 |
满足所有的$t_a=t_b$ |
||
13 |
|||
14 |
特殊性质S |
||
15 |
|||
16 |
|||
17 |
无 |
||
18 |
|||
19 |
≤3×105≤3×105 |
||
20 |
特殊性质S:保证nn为奇数,且对于所有i(0≤i≤n+1)i(0≤i≤n+1),假设hihi的最大值为mm。如果ii为偶数,保证hi=mhi=m。如果ii为奇数,保证hi<mhi<m。
本题共有 20 个测试点,每个测试点 5 分。对于所有的测试点,满足0<n≤105,0<m≤3×1050<n≤105,0<m≤3×105。对于每栋高楼,满足0<hi≤1080<hi≤108。
对于操作1与操作2,假设需要安装或拆除的收集器为xx,满足0<x≤n0<x≤n。对于操作1,保证之前第xx个收集器未安装。对于操作2,保证之前第xx个收集器已安装。
对于操作3,满足0<ta≤tb<1800<ta≤tb<180。
【提示】
本题中需要涉及角度与斜率之间的转化。请注意,在C++中可以调用三角函数为弧度制。
solution
啊啊啊调了一整天
atan2不会用,是(y,x)而不是(x,y)啊
cdq细节一直爆炸啊
小于写成小于等于啊
我fl=0就不操作,凭啥ans+=fl才能过啊
别人1.9k,我3k啊
最后真是一个个对拍才过
哇被气死
先用凸包求出太阳高度角范围:上凸壳上的点才会挡住它
然后就是经典三维偏序
qli>=li qri<=ri qt>=t
啊为什么这么难调
对了 几个技巧:
PI=acos(-1)或M_PI
精度较高
atan2(y,x) y,x!!!
返回的是弧度,角度=t*108/PI;
可能是负数,要判掉
还有我又用sort,特慢哈哈哈
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 100005
#define PI acos(-1)
using namespace std;
int n,T,top,tree[maxn*4],tot,ans[maxn*4];
struct node{
double li,ri;
int fl,id,q;
void bug()
{
cout<<li<<' '<<ri;
cout<<' '<<fl/*<<' '<<id<<' '<<q*/<<endl;
}
}s[maxn],a[maxn*4];
struct no{
int x,y;
}zh[maxn],h[maxn];
bool cmp(node a,node b){
return a.li>b.li||a.li==b.li&&a.ri<b.ri||a.li==b.li&&a.ri==b.ri&&a.id<b.id;
//return a.li>b.li||a.li==b.li&&fabs(a.fl)<fabs(b.fl);
}
bool R(node a,node b){
return a.ri<b.ri||a.ri==b.ri&&a.id<b.id;
}
void jia(int k,int val){
for(int i=k;i<=T;i+=i&-i)tree[i]+=val;
}
int ask(int k){
int sum=0;
for(int i=k;i;i-=i&-i)sum+=tree[i];
return sum;
}
void cdq(int l,int r){
if(l==r)return;
int mid=l+r>>1;
cdq(l,mid);cdq(mid+1,r);
sort(a+l,a+mid+1,R);sort(a+mid+1,a+r+1,R);
int i=l;
//cout<<l<<' '<<r<<endl;
for(int j=mid+1;j<=r;j++){
while(a[i].ri<a[j].ri&&i<=mid){
jia(a[i].id,a[i].fl);i++;
//cout<<"bbb ";
//a[i].bug();
}
if(a[j].fl==0){
ans[a[j].q]+=ask(a[j].id);
//cout<<"aaa "<<a[j].q<<' '<<a[j].id<<' '<<ans[a[j].q]<<endl;
}//a[j].bug();
}
for(int j=l;j<i;j++)jia(a[j].id,-a[j].fl);
}
no xl(no aa,no bb){
no t;t.x=aa.x-bb.x;t.y=aa.y-bb.y;
return t;
}
double cj(no a,no b){
return a.x*b.y-a.y*b.x;
}
int main()
{
cin>>n>>T;
for(int i=0;i<=n+1;i++){
scanf("%d",&h[i].y);h[i].x=i;
}
zh[1]=h[0];top=1;
for(int i=1;i<=n;i++){
while(top>1&&cj(xl(zh[top],zh[top-1]),xl(h[i],zh[top]))>=0)top--;
double x=h[i].x-zh[top].x,y=h[i].y-zh[top].y;
double t=atan2(y,x);t=t*180/PI;
//cout<<h[i].x<<' '<<h[i].y<<' '<<zh[top].x<<' '<<zh[top].y<<' '<<t<<endl;
t+=180;if(t>180)t=180;
s[i].li=t;
zh[++top]=h[i];
}
zh[1]=h[n+1];top=1;
for(int i=n;i>=1;i--){
while(top>1&&cj(xl(zh[top],zh[top-1]),xl(h[i],zh[top]))<=0)top--;
double x=h[i].x-zh[top].x,y=h[i].y-zh[top].y;
double t=atan2(y,x);t=t*180/PI;
//cout<<h[i].x<<' '<<h[i].y<<' '<<zh[top].x<<' '<<zh[top].y<<' '<<t<<endl;
t+=180;if(t>180)t=0;
s[i].ri=t;
zh[++top]=h[i];
}
//for(int i=1;i<=n;i++)cout<<s[i].li<<' '<<s[i].ri<<endl;
for(int i=1;i<=T;i++){
int op,t;
scanf("%d",&op);
if(op==1){
scanf("%d",&t);
a[i].li=s[t].li;a[i].ri=s[t].ri;
a[i].fl=1;
}
else if(op==2){
scanf("%d",&t);
a[i].li=s[t].li;a[i].ri=s[t].ri;
a[i].fl=-1;
}
else {
scanf("%lf%lf",&a[i].ri,&a[i].li);
// li left ri right
a[i].q=++tot;
}
a[i].id=i;
}
sort(a+1,a+T+1,cmp);
//for(int i=1;i<=T;i++)a[i].bug();
cdq(1,T);
for(int i=1;i<=tot;i++)printf("%d\n",ans[i]);
return 0;
}
/*
2 8
1 2 1 1
1 1
1 2
3 45 135
3 135 135
2 1
3 134 134
2 2
3 135 135
4 10
5 4 2 6 5 3
1 1
1 3
3 135 135
1 2
3 90 100
1 4
2 3
3 45 50
3 46 50
3 85 95
*/