Solar lamps
POI2014
题意
1.有n个灯,他们只会朝一个确定的夹角发光
2.每个灯被放在一个固定的地方,并且朝向同一个方向(指如果发光会朝同一个方向)
3.第i盏灯如果被至少K[i]盏灯照到那么他就会发光
4.现在按从1到n的顺序依次给每盏灯通电,即在第i个时刻给第i盏灯通电
5.问每盏灯在哪个时刻开始发光
解
1.先转换一下坐标
(方向乱七八糟看着不恶心么)
设新坐标为(a,b)
(x,y)=a(x1,y1)+b(x2,y2)
x=a*x1+b*x2
y=a*y1+b*y2
a=(-x*y1+y*x1)/(x1*y2-y1*x2)
b=(+x*y2-y*x2)/(x1*y2-y1*x2)
x1*y2-y1*x2 是定值
我们令这个定值为一个整数,就可以保证符号了
2.那么一盏灯(a,b),
可以照亮灯(x,y) {x>=a&&y>=n}
3.可以用树套树解决二维偏序问题,但是树套树要 n log n 2 n{\log{n}}^2 nlogn2的内存
4.考虑同时二分
对于每个l,r,L,R
mid=L+R>>1
1.先按照时间序(mid)分成两份询问
2.再把(l,r)的询问按y升序
3.如果碰到的询问Q[i]
Q[i].id<=mid
或者
当前它前面至少有Q[i].K盏灯已经亮了
那么把它塞入BIT中
4.亮了的(被照亮或被点亮)Q[i]放左边,没亮的放右边(放右边时把K-query(Q[i].y))
这样子不需要每次从头开始扫,每个区间就扫(L,R),因为前面区间可能产生的贡献已经计算过了
5.细节
如果这个照亮的角度是0°
即 两个向量在同一直线上,但是只有两个不共线的向量才能表示出任意向量,那么坐标转换此时就有问题了
但是重新写一下特殊情况有比较麻烦,所以我们强行把这两个向量掰开那么一丢丢角度(小到不影响结果)
具体代码
#include<bits/stdc++.h>
using namespace std;
const int M=200005;
int n,len,ans[M];
long long B[M];
int sum[M];
void add(int x,int a) {
while(x<=len) {
sum[x]+=a;
x+=-x&x;
}
}
int query(int x) {
int res=0;
while(x) {
res+=sum[x];
x-=-x&x;
}
return res;
}
struct node {
long long x,y;
int id,K;
bool operator <(const node&tmp)const {
if(x!=tmp.x)return x<tmp.x;
return y<tmp.y;
}
} Q[M],hc[M];
void solve(int l,int r,int L,int R) {
if(l>r||L>R)return;
int mid=L+R>>1;
int L1=l,R2=r;
sort(Q+l,Q+r+1);
for(int i=l; i<=r; i++) {
int k=query(Q[i].y);
if(Q[i].id<=mid||k>=Q[i].K) {
hc[L1++]=Q[i],ans[Q[i].id]=mid;
add(Q[i].y,1);
} else Q[i].K-=k,hc[R2--]=Q[i];
}
for(int i=l; i<L1; i++)add(hc[i].y,-1);
for(int i=l; i<=r; i++)Q[i]=hc[i];
solve(l,L1-1,L,mid-1);
solve(R2+1,r,mid+1,R);
}
int main() {
long long X1,Y1,X2,Y2;
int x,y;
scanf("%d %lld %lld %lld %lld",&n,&X1,&Y1,&X2,&Y2);
int f=1;
if(X1*Y2-Y1*X2==0) {
int m=max(abs(X1),abs(Y1));
int d=(2000000000ll-m+1)/m;
X1=X1*d+1,Y1=Y1*d;
}
if(X1*Y2-Y1*X2<0)f=-f;
len=0;
for(int i=1; i<=n; i++) {
scanf("%d %d",&x,&y);
long long a=-1ll*x*Y1+1ll*y*X1;
long long b=+1ll*x*Y2-1ll*y*X2;
a=a*f,b=b*f;
Q[i].x=a,Q[i].y=b;
B[++len]=b;
}
sort(B+1,B+1+len);
len=unique(B+1,B+1+len)-B-1;
for(int i=1; i<=n; i++) {
Q[i].id=i;
Q[i].y=lower_bound(B+1,B+1+len,Q[i].y)-B;
scanf("%d",&Q[i].K);
}
solve(1,n,1,n);
for(int i=1; i<=n; i++) {
printf("%d ",ans[i]);
}
return 0;
}