BZOJ3833: [Poi2014]Solar lamps

77 篇文章 0 订阅
32 篇文章 0 订阅

可以将给出的直线视作向量,那么当这两个向量不共线时(共线时情况类似),建立出以这两个向量为基底的坐标系,将坐标取反后,每盏灯(x,y)亮了后,能照亮的区域是(<=x,<=y),然后直接暴力弄这个东西就行了
因为不会写树套树qwq,我写了kd-tree,卡了半天卡过去了qwq
为了减小常数写了指针和一些奇奇怪怪的东西,代码可能不会很友好

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void read(int &x)
{
    char c; int sig=1;
    while(!((c=getchar())>='0'&&c<='9')) if(c=='-') sig=-1;
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
    x*=sig;
}
inline void up(int &x,const int &y){if(x<y)x=y;}
inline void down(int &x,const int &y){if(x>y)x=y;}
const int maxn = 210000;
const int maxd = 2;
const long double eps = 1e-10;
inline bool low(const long double x,const long double y){return x-y<-eps;}
inline bool same(const long double x,const long double y){return fabs(x-y)<eps;}

int ct1,ct2,ct3,ct4,ct5,ct6;
bool flag;
int n;
int X1,Y1,X2,Y2;
struct node{long double x,y;int i;}a[maxn];
inline bool cmpx(const node x,const node y){return low(x.x,y.x);}
inline bool cmpy(const node x,const node y){return low(x.y,y.y);}

struct kd_tree{int i,fa,u[maxd],d[maxd],p[maxd],ki,mn,fl;kd_tree *lc,*rc;}kd[maxn]; int root;
int To[maxn];
void pushdown(kd_tree *x)
{
    ++ct1;
    int fl=x->fl; x->fl=0;
    kd_tree *lc=x->lc,*rc=x->rc;
    if(lc!=NULL) lc->mn-=fl,lc->ki-=fl,lc->fl+=fl;
    if(rc!=NULL) rc->mn-=fl,rc->ki-=fl,rc->fl+=fl;
}
void pushup(kd_tree *x)
{
    ++ct2;
    x->mn=x->ki;
    if(x->lc) down(x->mn,x->lc->mn);
    if(x->rc) down(x->mn,x->rc->mn);
}
int cmpd;
inline bool cmp(const kd_tree &x,const kd_tree &y){return x.p[cmpd]<y.p[cmpd];}
int build(const int l,const int r,const int nowd)
{
    int x=l+r>>1;
    cmpd=nowd; std::nth_element(kd+l,kd+x,kd+r+1,cmp);
    for(int i=0;i<maxd;i++) kd[x].u[i]=kd[x].d[i]=kd[x].p[i];
    if(l!=x) 
    {
        int lc=build(l,x-1,!nowd); kd[x].lc=&kd[lc]; kd[lc].fa=x;
        for(int i=0;i<maxd;i++) down(kd[x].d[i],kd[lc].d[i]),up(kd[x].u[i],kd[lc].u[i]);
    }
    if(x!=r) 
    {
        int rc=build(x+1,r,!nowd); kd[x].rc=&kd[rc]; kd[rc].fa=x;
        for(int i=0;i<maxd;i++) down(kd[x].d[i],kd[rc].d[i]),up(kd[x].u[i],kd[rc].u[i]);
    }
    return pushup(&kd[x]),x;
}
int ans[maxn],nowi,oth;
int pos[maxd];
queue<int>q;
void clear(kd_tree *x)
{
    ++ct3;
    if(x->fl) pushdown(x);
    kd_tree *lc=x->lc,*rc=x->rc;
    if(lc!=NULL&&lc->mn==0) clear(lc);
    if(rc!=NULL&&rc->mn==0) clear(rc);
    if(x->ki==0) ans[x->i]=nowi,x->ki=2*n+2,q.push(To[x->i]);
    pushup(x);
}
void upd1(kd_tree *x)
{
    ++ct4;
    if(x->mn>oth||pos[0]<x->d[0]||x->u[0]<pos[0]||pos[1]<x->d[1]) return;
    if(x->d[0]==pos[0]&&x->u[0]==pos[0]&&x->u[1]<=pos[1]) 
    {
        x->fl++,x->ki--,x->mn--;
        if(x->mn==0) clear(x);
        return;
    }
    if(x->p[0]==pos[0]&&x->p[1]<=pos[1])
    {
        x->ki--; 
        if(!x->ki) ans[x->i]=nowi,x->ki=2*n+2,q.push(To[x->i]);
    }
    if(x->fl) pushdown(x);
    if(x->lc) upd1(x->lc);
    if(x->rc) upd1(x->rc);
    pushup(x);
}
void upd2(kd_tree *x)
{
    ++ct5;
    if(x->mn>oth||pos[0]<x->d[0]||pos[1]<x->d[1]) return;
    if(x->u[0]<=pos[0]&&x->u[1]<=pos[1])
    {
        x->fl++,x->ki--,x->mn--;
        if(x->mn==0) clear(x);
        return;
    }
    if(x->p[0]<=pos[0]&&x->p[1]<=pos[1])
    {
        x->ki--; 
        if(!x->ki) ans[x->i]=nowi,x->ki=2*n+2,q.push(To[x->i]);
    }
    if(x->fl) pushdown(x);
    if(x->lc) upd2(x->lc);
    if(x->rc) upd2(x->rc);
    pushup(x);
}

int t[maxn],tp;

int main()
{
    read(n); read(X1),read(Y1); read(X2),read(Y2);

    flag=(ll)X1*Y2==(ll)X2*Y1;
    long double k=X1?(long double)Y1/X1:0.0,al=(long double)X1*Y2-(long double)X2*Y1;
    for(int i=1;i<=n;i++)
    {
        int x,y; read(x); read(y);
        long double kk;
        if(flag) kk=!X1?x:(long double)y-k*x;
        else kk=((long double)X1*y-(long double)x*Y1)/al;
        a[i].x=-kk;
        if(flag) kk=!X1?((long double)y/Y1):(long double)x/X1;
        else kk=X1?((long double)x-kk*X2)/X1:((long double)y-kk*Y2)/Y1;
        a[i].y=-kk;
        a[i].i=i;
    }
    sort(a+1,a+n+1,cmpx);
    for(int i=1,las=0;i<=n;i++)
    {
        if(!same(a[i].x,a[i-1].x))las++;
        kd[a[i].i].p[0]=las;
    }
    sort(a+1,a+n+1,cmpy);
    for(int i=1,las=0;i<=n;i++)
    {
        if(!same(a[i].y,a[i-1].y))las++;
        kd[a[i].i].p[1]=las;
    }
    for(int i=1;i<=n;i++) read(kd[i].ki),kd[i].i=i;

    root=build(1,n,0);
    for(int i=1;i<=n;i++) To[kd[i].i]=i;
    for(nowi=1,oth=n;nowi<=n;nowi++) if(!ans[nowi])
    {
        q.push(To[nowi]);
        while(!q.empty())
        {
            const int x=q.front(); q.pop();
            ans[kd[x].i]=nowi; kd[x].ki=2*n+2;
            int tmp=x; tp=0; while(tmp) t[++tp]=tmp,tmp=kd[tmp].fa;
            for(int j=tp;j>=1;j--) if(kd[t[j]].fl) pushdown(&kd[t[j]]);
            for(int j=1;j<=tp;j++) pushup(&kd[t[j]]);

            pos[0]=kd[x].p[0],pos[1]=kd[x].p[1];
            if(flag) upd1(&kd[root]);
            else upd2(&kd[root]);
            oth--;
        }
    }
    for(int i=1;i<n;i++) printf("%d ",ans[i]);
    printf("%d\n",ans[n]);
    //puts("");
    //printf("%d %d %d %d %d\n",ct1,ct2,ct3,ct4,ct5);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值