CF 243D Cubes(线段树)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

题目:给出n*n个格子,每个格子上有若干个单位立方体。从无穷远有一片光线,问最多能照到多少个立方体

http://codeforces.com/contest/243/problem/D 

我们对于每个格子,通过向量求出某个区间,表示这个区间的发射的光线可以照射到立方体上。

至于 这个点通过向量怎么映射的怎么解决呢。

首先我们考虑一下区间[L,R]。我们考虑3个点(0,0)(vx,vy)(x,y)怎么表示(x,y)在向量垂直上的映射呢。

通过叉积,求出夹角就可以相对的表示“左右关系”。

利用点积表示"前后关系"

对于一个格子,我们考虑的不是一个点,求出4个点的叉积点积,取最小值为左端点,最大值为右端点,就得到一个区间为格子的映射,取点积的最小值(最前面的)表示前后关系。

将坐标离散化一下,线段树中保存的是当前区间的最低的阻挡高度。

也就是线段树中保存的是最小值,而我们用最大值去更新。

这题点非常多啊,10e6,卡爆了,勉强常数优化过去。

(艹这样的题解也能发?还是去这里吧http://blog.csdn.net/dslovemz/article/details/8203366

不错的题目,欢迎私聊,不过也有神做法,效率很高

#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<queue>
#define inf 100000005
#define M 200005
#define N 2100000
#define maxn 300005
#define eps 1e-10
#define zero(a) fabs(a)<eps
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
//#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define lson step<<1
#define rson step<<1|1
#define MOD 1000000009
#define sqr(a) ((a)*(a))
#define Key_value ch[ch[root][1]][0]
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
vector<int>coor;
int n,vx,vy;
inline int min(int a,int b ){return a<b?a:b;}
inline int max(int a,int b ){return a>b?a:b;}
struct Cube
{
    int l,r,h,d;
    inline void Init(int x,int y,int _h)
    {
        h=_h;
        vector<int>a,b;
        for(int xx=x;xx<=x+1;xx++)
        {
            for(int yy=y;yy<=y+1;yy++)
            {
                a.pb(xx*vy-yy*vx);
                b.pb(xx*vx+yy*vy);
            }
        }
        l=*min_element(a.begin(),a.end())*2;
        r=*max_element(a.begin(),a.end())*2;
        d=*min_element(b.begin(),b.end());
        coor.pb(l);coor.pb(r);
    }
    bool operator<(const Cube c)const
    {
        return d<c.d;
    }
};
struct Node
{
    int left,right;
    int lazy,val;
}L[N<<2];
vector<Cube>cube;
map<int,int>mp;
void Push_Up(int step)
{
    L[step].val=min(L[lson].val,L[rson].val);
}
void Push_Down(int step)
{
    if(L[step].lazy)
    {
        L[lson].lazy=max(L[step].lazy,L[lson].lazy);
        L[rson].lazy=max(L[step].lazy,L[rson].lazy);
        L[lson].val=max(L[step].lazy,L[lson].val);
        L[rson].val=max(L[step].lazy,L[rson].val);
        L[step].lazy=0;
    }
}
void Bulid(int step,int l,int r)
{
    L[step].left=l;
    L[step].right=r;
    int m=(l+r)/2;
    L[step].lazy=L[step].val=0;
    if(l==r) return ;
    Bulid(lson,l,m);
    Bulid(rson,m+1,r);
}
inline void Update(int step,int l,int r,int c)
{
    if(L[step].left==l&&L[step].right==r)
    {
        L[step].lazy=max(L[step].lazy,c);
        L[step].val=max(L[step].val,c);
        return ;
    }
    Push_Down(step);
    int m=(L[step].left+L[step].right)>>1;
    if(r<=m) Update(lson,l,r,c);
    else if(l>m) Update(rson,l,r,c);
    else
    {
        Update(lson,l,m,c);
        Update(rson,m+1,r,c);
    }
    Push_Up(step);
}
inline int Query(int step,int l,int r)
{
    if(L[step].left==l&&L[step].right==r)
    {
        return L[step].val;
    }
    Push_Down(step);
    int m=(L[step].left+L[step].right)>>1;
    if(r<=m) return Query(lson,l,r);
    else if(l>m) return Query(rson,l,r);
    else return min(Query(lson,l,m),Query(rson,m+1,r));
}
int main()
{
    while(scanf("%d%d%d",&n,&vx,&vy)!=EOF)
    {
        cube.clear();
        mp.clear();
        int first=0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                int h;
                scanf("%d",&h);
                if(!h){if(first) continue; first=1; }
                Cube tmp;tmp.Init(i,j,h);
                cube.pb(tmp);
            }
        }
        sort(coor.begin(),coor.end());
        unique(coor.begin(),coor.end());
        sort(cube.begin(),cube.end());
        n=coor.size();
        Bulid(1,1,n);
        LL ans=0;
        for(int i=0;i<n;i++) mp[coor[i]]=i+1;
        for(int i=0;i<cube.size();i++)
        {
            cube[i].l=mp[cube[i].l];
            cube[i].r=mp[cube[i].r]-1;
        //    cout<<cube[i].l<<" "<<cube[i].r<<endl;
        }
        for(int i=0;i<cube.size();i++)
        {
            int ret=Query(1,cube[i].l,cube[i].r);
            if(ret<cube[i].h)
            {
                ans+=cube[i].h-ret;
                Update(1,cube[i].l,cube[i].r,cube[i].h);
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值