csp-s模拟测试90「光线追踪,临面合并」

光线追踪

30分暴力就是看每个光线和每个矩形的下边界和左边界交点

发现询问很难,

离线下来操作,

可以把角度离散化,转化为区间赋值,单点查询问题

每次就是给属于下边界角度内赋max,左边界角度内赋max

我突然感觉没什么可写的

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 5471745
struct node{
    ll ord,x;
    node(){}
    node(const ll &a,const ll &b){ord=a,x=b;}
};    
node Min(node a,node b){
    return a.x<b.x?a:a.x==b.x?(a.ord<b.ord?b:a):b;
}
ll pan(ll x){
    if(x>1e9) return 0;
    return x;
}
struct tree{
    node w[A];
    ll cl[A],cr[A];
    void built(ll x,ll l,ll r){
        cl[x]=l,cr[x]=r;
        w[x]=node(1e9+7,1e9+7);
        if(l==r){
            return ;
        }
        ll mid=(l+r)>>1;
        built(x<<1,l,mid);
        built(x<<1|1,mid+1,r);
    }
    void change(ll x,ll l,ll r,ll ord,ll val){
        if(cl[x]>=l&&cr[x]<=r){
//            printf("l=%lld r=%lld w[].val=%lld val=%lld\n",cl[x],cr[x],w[x].x,val);
            w[x]=Min(w[x],node(ord,val));
            return ;
        }
        ll mid=(cl[x]+cr[x])>>1;
        if(mid>=l) change(x<<1,l,r,ord,val);
        if(mid<r) change(x<<1|1,l,r,ord,val);
    }
    node ask(ll x,ll pla){
        if(cl[x]==cr[x]) return w[x];
        node p;
        ll mid=(cl[x]+cr[x])>>1;
        if(mid>=pla) p=ask(x<<1,pla);
        else p=ask(x<<1|1,pla);
        return Min(p,w[x]);//标记永久化
    }
}X,Y;
ll x[A],xx[A],y[A],yy[A],opt[A];
ll mnx0=1e9+7,mnxid,mny0=1e9+7,mnyid,cnt,q;
long double lsh[A];
long double cl(ll x){
    if(x) return 1.0*x;
    return 1e-7L;
}
int main(){
    scanf("%lld",&q);
    for(ll i=1;i<=q;i++){
        scanf("%lld",&opt[i]);
        if(opt[i]==1){
            scanf("%lld%lld%lld%lld",&x[i],&y[i],&xx[i],&yy[i]);
            lsh[++cnt]=1.0L*y[i]/cl(x[i]),lsh[++cnt]=1.0L*yy[i]/cl(x[i]),lsh[++cnt]=1.0L*y[i]/cl(xx[i]);
        }
        else {
            scanf("%lld%lld",&x[i],&y[i]);
            if(x[i]) lsh[++cnt]=1.0L*y[i]/x[i];
        }
    }
    sort(lsh+1,lsh+cnt+1);
    ll len=unique(lsh+1,lsh+cnt+1)-lsh-1;
    X.built(1,1,len),Y.built(1,1,len);
    for(ll i=1;i<=q;i++){
        if(opt[i]==1){
            if(!x[i])if(mnx0>=y[i])mnx0=y[i],mnxid=i;
            if(!y[i])if(mny0>=x[i])mny0=x[i],mnyid=i;
            ll x1=lower_bound(lsh+1,lsh+len+1,1.0L*y[i]/cl(x[i]))-lsh;
            ll x3=lower_bound(lsh+1,lsh+len+1,1.0L*y[i]/cl(xx[i]))-lsh;
            ll x2=lower_bound(lsh+1,lsh+len+1,1.0L*yy[i]/cl(x[i]))-lsh;
//            printf("i=%lld\n",i);
            X.change(1,x1,x2,i,x[i]),Y.change(1,x3,x1,i,y[i]);
        }
        else {
            if(!x[i]){printf("%lld\n",mnxid);continue;}
            if(!y[i]){printf("%lld\n",mnyid);continue;}
//            printf("i=%lld lower_bound(lsh+1,lsh+1+len,1.0L*y[i]/x[i])-lsh=%lld\n",i,1ll*(lower_bound(lsh+1,lsh+1+len,1.0L*y[i]/x[i])-lsh));
            node a1=X.ask(1,lower_bound(lsh+1,lsh+1+len,1.0L*y[i]/x[i])-lsh),
              a2=Y.ask(1,lower_bound(lsh+1,lsh+1+len,1.0L*y[i]/x[i])-lsh);
            ll fx=a1.x,fy=a2.x;
//            printf("fx=%lld fy=%lld\n",fx,fy);
            if(fx*y[i]==fy*x[i])printf("%lld\n",pan(max(a1.ord,a2.ord)));
            else if(fx*y[i]<fy*x[i])printf("%lld\n",pan(a1.ord));
            else printf("%lld\n",pan(a2.ord));
        }
    }
}
View Code

临面合并

奇怪的数据范围应该给了一定的提示,8以内就基本是明示状压了

状态定义挺神的二进制下有一个1代表以当前点为右端点向左延伸出一个矩形

例如(假设原图是1 1 1 1)那么当前是0 1 0 1 表示两个矩形

判断一下是否可以与上面合并,减去相同贡献

过程可以预处理

不要用单调指针处理,单调指针细节特别多,

预处理

void fg(ll x){
    for(ll i=0;i<=maxn;i++){
        if((i&least[x])!=least[x]) continue ;
        if((i|maxx[x])!=maxx[x]) continue ;
        belong[x].push_back(i);
        ll cnt=0;
        for(ll j=1;j<=m;j++){
            if((i>>(j-1))&1)
                dl[++cnt]=j;
        }
        for(ll j=1;j<=cnt;j++){
            if(j==1) v[x][i].push_back(base[dl[1]]&a[x]);
            else v[x][i].push_back((base[dl[j]]^base[dl[j-1]])&a[x]);
        }
    }
}

减去相同贡献

                ll cnt=v[i][now].size();
                for(ll j1=0;j1<v[i][now].size();j1++)
                    for(ll j2=0;j2<v[i-1][last].size();j2++){
                        ll tox=v[i][now][j1],toy=v[i-1][last][j2];
                        if(tox==toy){
//                            printf("tox=%lld toy=%lld\n",tox,toy);
                            cnt--;
                        }
                    }

 出题人题解

posted @ 2019-11-08 06:30  znsbc  阅读(262)  评论(0编辑  收藏  举报