Codeforces 331D3-线段树+扫描线+倍增

传送门

题意:

在n*n的坐标内给出一些箭头,给出一些出发点、出发方向以及出发时间,遇到箭头就需要改变方向为箭头的方向,对每个出发点求最后能走到哪

数据范围1e5

Solution:

口胡起来特别简单:对于不同方向的箭头和出发点分别用线段树+扫描线建出相应的图,最后在建出的图上跑倍增就可以了
我们可以把出发点看做没有长度的箭头,就可以和箭头一起搞了,在建图时我们可以添加一个中间点作为一个箭头延长后与另一个箭头的交点,注意虽然题目上说箭头不能重合,交叉,但是如果我们把出发点看成箭头的话会出现箭头包含箭头的情况,这里和走到边界时都需要特殊处理一下
另外,由于倍增时可能会爆longlong,注意到时间是小于1e18的,所以我们倍增时如果发现倍增后的值大于1e18,就可以把这个值强制赋值为大于1e18的数

写起来简直要命。。。。。。

相当及其超级练习代码能力pwp

代码:

#include
#include
#include
#define RR 1
#define LL 2
#define DD 3
#define UU 4 
#define debug(x) cerr<<#x<<"="<" "
using namespace std;
const int N=200010;
int n,b,x,y,tot,q;
int val[2*N],to[2*N];
int st[2*N],tp;
char s[2];
int go[2*N][70];
long long dis[2*N][70];
int vis[2*N];
int aabs(int a){return a<0?-a:a;}
struct arrow{
    int x1,y1,x2,y2,id,tag,dir;
    int maxx,minx,maxy,miny;
    void get()
    {
        maxx=max(x1,x2);
        minx=min(x1,x2);
        maxy=max(y1,y2);
        miny=min(y1,y2);
    }
}a[2*N],A[2*N];//1R 2L 3D 4U 
long long t[N];
struct tree{
    int l,r,tag,v;
}tr[4*N];
int ansx[N],ansy[N];
int dx[5]={0,1,-1,0,0};
int dy[5]={0,0,0,-1,1};
void build(int i,int l,int r)
{
    tr[i].tag=-1;tr[i].l=l,tr[i].r=r;tr[i].v=-1;
    if (l==r) return;
    int mid=l+r>>1;
    build(i<<1,l,mid);build(i<<1|1,mid+1,r);
}
void pushdown(int i)
{
    if (tr[i].tag!=-1)
    {
        if (tr[i].l==tr[i].r) tr[i].v=tr[i].tag;
        else tr[i<<1].tag=tr[i].tag,tr[i<<1|1].tag=tr[i].tag;
        tr[i].tag=-1;
    }
}
void modify(int i,int l,int r,int v)
{
    int L=tr[i].l,R=tr[i].r;
    if (l>R||L>r) return;
    pushdown(i);
    if (l<=L&&R<=r) {if (L==R) tr[i].v=v;else tr[i].tag=v;return;}
    modify(i<<1,l,r,v);modify(i<<1|1,l,r,v);
}
int query(int i,int pos)
{
    int L=tr[i].l,R=tr[i].r;
    pushdown(i);
    if (L==R) return tr[i].v;
    int mid=L+R>>1;
    if (mid>=pos) return query(i<<1,pos);else return query(i<<1|1,pos);
}
void addedg(int x,int y,int v){to[x]=y,val[x]=v;}
bool cmp1(arrow a,arrow b){return (a.maxx==b.maxx)?a.taga.maxx>b.maxx;}
bool cmp2(arrow a,arrow b){return (a.minx==b.minx)?a.taga.minx;}
bool cmp4(arrow a,arrow b){return (a.maxy==b.maxy)?a.taga.maxy>b.maxy;}
bool cmp3(arrow a,arrow b){return (a.miny==b.miny)?a.taga.miny;}
int main()
{
    scanf("%d%d",&n,&b);
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
        a[i].tag=0;a[i].id=i;
        if (a[i].x2==a[i].x1&&a[i].y1==a[i].y2) {n--,i--;continue;}
        if (a[i].x1<a[i].x2) a[i].dir=1;
        else if (a[i].x1>a[i].x2) a[i].dir=2;
        else if (a[i].y1<a[i].y2) a[i].dir=4;
        else if (a[i].y1>a[i].y2) a[i].dir=3;
    }
    scanf("%d",&q);
    for (int i=1;i<=q;i++)
    {
        scanf("%d%d%s%I64d",&x,&y,s,&t[i]);
        a[i+n].x1=x,a[i+n].x2=x;
        a[i+n].y1=y,a[i+n].y2=y;
        a[i+n].tag=1;a[i+n].id=i+n;
        if (s[0]=='R') a[i+n].dir=1;
        else if (s[0]=='L') a[i+n].dir=2;
        else if (s[0]=='D') a[i+n].dir=3;
        else a[i+n].dir=4;
    }
    tot=n+q;
    for (int i=1;i<=n+q;i++) a[i].get();
    //R
    sort(a+1,a+1+n+q,cmp1);
    build(1,0,b);
    for (int i=1;i<=n+q;i++)
    {
        if (a[i].tag==0)
        {
            if (a[i].dir==LL) modify(1,a[i].y1,a[i].y2,i);
            else if (a[i].dir==UU) modify(1,a[i].y1,a[i].y2,i);
            else if (a[i].dir==DD) modify(1,a[i].y2,a[i].y1,i);
        }
        if (a[i].dir==RR)
        {
            int nw=query(1,a[i].y1);

            tot++;
            a[tot].id=tot;
            a[tot].y1=a[i].y1;
            if (nw!=-1)
            {
                if (a[nw].dir==LL) addedg(tot,a[nw].id,max(0,a[i].x2-a[nw].x2)),a[tot].x1=max(a[i].x2,a[nw].x2);
                else addedg(tot,a[nw].id,aabs(a[nw].y2-a[i].y2)),a[tot].x1=a[nw].x1;
                addedg(a[i].id,tot,max(0,a[nw].x2-a[i].x2));
            }
            else
            {
                a[tot].x1=b;
                addedg(a[i].id,tot,b-a[i].x2);
                addedg(tot,tot,1);
            }

        }
    }
    //L
    sort(a+1,a+1+n+q,cmp2);
    build(1,0,b);
    for (int i=1;i<=n+q;i++)
    {
        if (a[i].tag==0)
        {
            if (a[i].dir==RR) modify(1,a[i].y1,a[i].y2,i);
            else if (a[i].dir==UU) modify(1,a[i].y1,a[i].y2,i);
            else if (a[i].dir==DD) modify(1,a[i].y2,a[i].y1,i);
        }
        if (a[i].dir==LL)
        {
            int nw=query(1,a[i].y1);
            tot++;
            a[tot].id=tot;
            a[tot].y1=a[i].y1;
            if (nw!=-1)
            {
                if (a[nw].dir==RR) addedg(tot,a[nw].id,max(0,a[nw].x2-a[i].x2)),a[tot].x1=min(a[i].x2,a[nw].x2);
                else addedg(tot,a[nw].id,aabs(a[nw].y2-a[i].y2)),a[tot].x1=a[nw].x1;
                addedg(a[i].id,tot,max(0,a[i].x2-a[nw].x2));
            }
            else
            {
                a[tot].x1=0;
                addedg(a[i].id,tot,a[i].x2);
                addedg(tot,tot,1);
            }

        }
    }

    //D
    sort(a+1,a+1+n+q,cmp3);
    build(1,0,b);
    for (int i=1;i<=n+q;i++)
    {
        if (a[i].tag==0)
        {
            if (a[i].dir==LL) modify(1,a[i].x2,a[i].x1,i);
            else if (a[i].dir==UU) modify(1,a[i].x1,a[i].x2,i);
            else if (a[i].dir==RR) modify(1,a[i].x1,a[i].x2,i);
        }
        if (a[i].dir==DD)
        {
            int nw=query(1,a[i].x1);
            tot++;
            a[tot].id=tot;
            a[tot].x1=a[i].x1;
            if (nw!=-1)
            {
                if (a[nw].dir==UU) addedg(tot,a[nw].id,max(0,a[nw].y2-a[i].y2)),a[tot].y1=min(a[i].y2,a[nw].y2);
                else addedg(tot,a[nw].id,aabs(a[nw].x2-a[i].x2)),a[tot].y1=a[nw].y1;
                addedg(a[i].id,tot,max(0,a[i].y2-a[nw].y2));
            }
            else
            {
                a[tot].y1=0;
                addedg(a[i].id,tot,a[i].y2);
                addedg(tot,tot,1);
            }
        }
    }
    //U
    sort(a+1,a+1+n+q,cmp4);
    build(1,0,b);
    for (int i=1;i<=n+q;i++)
    {

        if (a[i].tag==0)
        {
            if (a[i].dir==LL) modify(1,a[i].x2,a[i].x1,i);
            else if (a[i].dir==DD) modify(1,a[i].x1,a[i].x2,i);
            else if (a[i].dir==RR) modify(1,a[i].x1,a[i].x2,i);
        }
        if (a[i].dir==UU)
        {
            int nw=query(1,a[i].x1);
            tot++;
            a[tot].id=tot;
            a[tot].x1=a[i].x1;
            if (nw!=-1)
            {
                if (a[nw].dir==DD) addedg(tot,a[nw].id,max(0,a[i].y2-a[nw].y2)),a[tot].y1=max(a[i].y2,a[nw].y2);
                else addedg(tot,a[nw].id,aabs(a[nw].x2-a[i].x2)),a[tot].y1=a[nw].y1;
                addedg(a[i].id,tot,max(0,a[nw].y2-a[i].y2));
            }
            else
            {
                a[tot].y1=b;
                addedg(a[i].id,tot,b-a[i].y2);
                addedg(tot,tot,1);
            }

        }
    }
    for (int i=n+q+1;i<=tot;i++) a[i].x2=a[i].x1,a[i].y2=a[i].y1;
    for (int i=1;i<=tot;i++) A[a[i].id]=a[i];
    for (int i=1;i<=tot;i++) dis[i][0]=val[i],go[i][0]=to[i];
    for (int i=1;i<=60;i++)
        for (int j=1;j<=tot;j++)
        {
            go[j][i]=go[go[j][i-1]][i-1];
            dis[j][i]=dis[j][i-1]+dis[go[j][i-1]][i-1];
            if (dis[j][i]>1e18) dis[j][i]=2e18;
        }
    for (int i=1;i<=tot;i++)
    {
        if (a[i].tag==1)
        {
            int pos=a[i].id;
            long long nw=t[a[i].id-n];
            for (int i=60;i>=0;i--)
            {
                if (nw-dis[pos][i]>=0)
                    nw-=dis[pos][i],pos=go[pos][i];
            }
            int d=0;
            if (A[pos].x1<A[to[pos]].x2) d=1;
            else if (A[pos].x1>A[to[pos]].x2) d=2;
            else if (A[pos].y1<A[to[pos]].y2) d=4;
            else if (A[pos].y1>A[to[pos]].y2) d=3;
            ansx[a[i].id-n]=A[pos].x2+dx[d]*nw; 
            ansy[a[i].id-n]=A[pos].y2+dy[d]*nw;

        }
    }
    for (int i=1;i<=q;i++) printf("%d %d\n",ansx[i],ansy[i]);
}

你可能感兴趣的:(线段树,倍增,码农题,扫描线)