POI2014 Solar Lamps

第一件要干的事就是把它给你的坐标用它给你的两个向量表示出来,事实上这件事就够令人发狂了…

所以开始解方程.

我们有

{ax1+bx2=Xay1+by2=Y

解得:
a=Xy2Yx2x1y2x2y1b=Xy1Yx1x2y1x1y2

然后我们发现上下两个数的分母是相反数,所以我们可以取一个正的,使得忽视掉这个数之后,a,b的数值大小不发生改变.

那么如果在变换后Q[i]能够照到Q[j],那么一定有

Q[i].x<=Q[j].x,Q[i].y<=Q[j].y

而这个之后可以通过排序后通过树状数组来维护.

这样我们现在的问题就是要知道什么时候它会第一次亮.

那么考虑一下分治.

现在我们有一个时间区间[L,R],以及一个灯的区间[l,r].

然后取一半得到一个时间的mid,然后就可以知道哪些灯是现在就可以点亮的了,而哪些灯还要再过一会才可以点亮,那么这些灯我们对于它的K,我们把现在能够照到它的灯的数量减去,以后不予以计算.

这样的话,我们就可以把这些灯分成两份:在mid时间前可以被点完的,以及在mid时间前不能够被点完的.

然后继续递归去求解就行了.

#include
#include
#include
#include
#include
#define M 200005
#define LL long long
#define y1 saiff
using namespace std;
templatevoid Rd(T &res){
    res=0;char p;int k=1;
    while(p=getchar(),!(p>='0'&&p<='9')&&(p!='-'));
    if(p=='-')k=-1,p=getchar();
    do{
        res=(res<<1)+(res<<3)+(p^48);
    }while(p=getchar(),p>='0');
    res*=k;
}
int n,x1,x2,y1,y2;
struct W{
    LL x,y;
    int id,K;
    bool operator <(const W &a)const{
        if(x!=a.x)return xreturn yint psz=0;
void dop(int &x,int &y){
    int tmp=max(abs(x),abs(y));
    int pl=(2000000000LL+tmp+2-1)/tmp;
    x*=pl,y*=pl;x++;
}
struct Bit{
    int Tree[M];
    void Add(int x,int v){
        while(xint Sum(int x){
        int re=0;
        while(x){
            re+=Tree[x];
            x-=x&(-x);
        }
        return re;
    }
}T;
struct IHUS{
    int ans[M];
    void tot_solve(int L,int R,int l,int r){
        if(l>r)return;
        if(L==R){
            for(int j=l;j<=r;j++)ans[Q[j].id]=L;
            return;
        }
        int mid=(L+R)>>1,Mid=l;
        sort(Q+l,Q+r+1);

        for(int i=l;i<=r;i++){
            if(Q[i].id<=mid){
                T.Add(Q[i].y,1);
                swap(Q[i],Q[Mid++]);
                continue;
            }else {
                int tmp=T.Sum(Q[i].y);
                if(tmp>=Q[i].K){
                    T.Add(Q[i].y,1);
                    swap(Q[i],Q[Mid++]);
                }else Q[i].K-=tmp;
            }
        }

        for(int i=l;i1);

        tot_solve(L,mid,l,Mid-1);
        tot_solve(mid+1,R,Mid,r);
    }
    void solve(){
        for(int i=1;i<=n;i++){
            LL nx=(1LL*x2*Q[i].y-1LL*Q[i].x*y2),ny=(1LL*Q[i].x*y1-1LL*x1*Q[i].y);
            Q[i].x=nx,Q[i].y=ny;
        }
        psz=0;
        for(int i=1;i<=n;i++)pl[psz++]=Q[i].x;
        sort(pl,pl+psz);psz=unique(pl,pl+psz)-pl;
        for(int i=1;i<=n;i++)Q[i].x=lower_bound(pl,pl+psz,Q[i].x)-pl+1;
        psz=0;
        for(int i=1;i<=n;i++)pl[psz++]=Q[i].y;
        sort(pl,pl+psz);psz=unique(pl,pl+psz)-pl;
        for(int i=1;i<=n;i++)Q[i].y=lower_bound(pl,pl+psz,Q[i].y)-pl+1;
        sort(Q+1,Q+n+1);
        tot_solve(1,n,1,n);
        for(int i=1,f=0;i<=n;i++){
            if(f)putchar(' ');f=true;
            printf("%d",ans[i]);
        }
        putchar('\n');
    }
}Nom;
int main(){
//  freopen("lam.in","r",stdin);
//  freopen("lam.out","w",stdout);
    Rd(n),Rd(x1),Rd(y1),Rd(x2),Rd(y2);
    for(int i=1;i<=n;i++)Rd(Q[i].x),Rd(Q[i].y);
    for(int i=1;i<=n;i++)Rd(Q[i].K),Q[i].id=i;
    if(1LL*x1*y2==1LL*x2*y1)dop(x1,y1);
    if(1LL*x2*y1-1LL*x1*y2<0)swap(x1,x2),swap(y1,y2);
    Nom.solve();
    return 0;
}

你可能感兴趣的:(poi,分治,---树状数组,---斜率优化)