bzoj 3519 线段树

题意说的什么jb玩意
写完之后我都开始怀疑人生了。。。

每行每列开个线段树,维护加点删点找前驱后继(好像可以set)
第一问找询问的点两个方向的第一个点,看是不是相同颜色。
第二问把一开始能选的放进一个队列,然后每删除一个点只会影响到上下左右第一个点的答案。
一坨判断

#include <bits/stdc++.h>
using namespace std;
#define N 110000
#define M 9100000
#define ls l,mid,ch[now][0]
#define rs mid+1,r,ch[now][1]
char s1[11],s2[11];
int r,c,n,m,cnt,bod,ans,top;
int X1[N],Y1[N],X2[N],Y2[N],vis[N];
int px[M],pn[M],vx[M],vn[M],ch[M][2];
struct node
{
    int x,y,pos;
    node(){}
    node(int x,int y,int pos):x(x),y(y),pos(pos){}
}st[N];
queue<node>que;
int decode(char c)
{return c=='R' ? 0:(c=='U' ? 1:(c=='L' ? 2:3));}
struct Seg_tree
{
    int root;
    void upd(int x,int pos,int v)
    {
        if(!px[x]||pos>px[x])
            {px[x]=pos;vx[x]=v;}
        if(!pn[x]||pos<pn[x])
            {pn[x]=pos;vn[x]=v;}
    }
    void pushup(int x)
    {
        for(int i=0,t;i<=1;i++)if(t=ch[x][i])
        {
            if(px[t]&&(!px[x]||px[t]>px[x]))
                {px[x]=px[t];vx[x]=vx[t];}
            if(pn[t]&&(!pn[x]||pn[t]<pn[x]))
                {pn[x]=pn[t];vn[x]=vn[t];}
        }
    }
    void insert(int l,int r,int &now,int pos,int v)
    {
        if(!now)now=++cnt;
        upd(now,pos,v);
        if(l==r)return;
        int mid=(l+r)>>1;
        if(mid>=pos)insert(ls,pos,v);
        else insert(rs,pos,v);
    }
    int pre(int l,int r,int now,int pos)
    {
        if(!now)return 0;
        if(r<=pos)return vx[now];
        int mid=(l+r)>>1;
        if(mid>=pos)
            return pre(ls,pos);
        else
        {
            int ret=pre(rs,pos);
            if(ret)return ret;
            return pre(ls,pos);
        }
    }
    int nex(int l,int r,int now,int pos)
    {
        if(!now)return 0;
        if(l>=pos)return vn[now];
        int mid=(l+r)>>1;
        if(mid>=pos)
        {
            int ret=nex(ls,pos);
            if(ret)return ret;
            return nex(rs,pos);
        }
        else return nex(rs,pos);
    }
    int find(int l,int r,int now,int pos)
    {
        if(!now||!vx[now])return 0;
        if(l==r)return 1;
        int mid=(l+r)>>1;
        if(mid>=pos)return find(ls,pos);
        else return find(rs,pos); 
    }
    void del(int l,int r,int now,int pos)
    {
        px[now]=pn[now]=vx[now]=vn[now]=0;
        if(l==r)return;
        int mid=(l+r)>>1;
        if(mid>=pos)del(ls,pos);
        else del(rs,pos);
        pushup(now);
    }
    void insert(int x,int v)
        {insert(1,bod,root,x,v);}
    int pre(int x)
        {return pre(1,bod,root,x);}
    int nex(int x)
        {return nex(1,bod,root,x);}
    int find(int x)
        {return find(1,bod,root,x);}
    void del(int x)
        {del(1,bod,root,x);}
}X[N],Y[N];
void insert(int x)
{
    X[Y1[x]].insert(X1[x],x);
    X[Y2[x]].insert(X2[x],x);
    Y[X1[x]].insert(Y1[x],x);
    Y[X2[x]].insert(Y2[x],x);
}
void del(int x)
{
    X[Y1[x]].del(X1[x]);
    X[Y2[x]].del(X2[x]);
    Y[X1[x]].del(Y1[x]);
    Y[X2[x]].del(Y2[x]);  
}
void init()
{
    ans=0;
    for(int i=1;i<=cnt;i++)
        px[i]=pn[i]=vx[i]=vn[i]=ch[i][0]=ch[i][1]=0;
    for(int i=1;i<=bod;i++)
        X[i].root=Y[i].root=0;
    cnt=0;
    for(int i=1;i<=n;i++)
        insert(i);
}
int poss(int x,int y)
{return X[y].find(x);}
int move(int x,int y,int d)
{
    if(d==0)return Y[x].nex(y);
    if(d==1)return X[y].pre(x);
    if(d==2)return Y[x].pre(y);
    return X[y].nex(x);
}
void free(int x)
{
    if(vis[x])return;
    int p1,p2;
    if(X1[x]==X2[x])
    {
        if(Y2[x]-Y1[x]==1)return;
        p1=Y[X1[x]].pre(Y1[x]+1);
        p2=Y[X1[x]].nex(Y1[x]+1);
        if(p1==x&&p2==x)
            {vis[x]=1;que.push(node(X1[x],Y1[x]+1,x));}
    }
    else if(Y1[x]==Y2[x])
    {
        if(X2[x]-X1[x]==1)return;
        p1=X[Y1[x]].pre(X1[x]+1);
        p2=X[Y1[x]].nex(X1[x]+1);
        if(p1==x&&p2==x)
            {vis[x]=1;que.push(node(X1[x]+1,Y1[x],x));}
    }
    else if(Y1[x]<Y2[x])
    {
        p1=X[Y1[x]].pre(X2[x]);
        p2=Y[X2[x]].nex(Y1[x]);
        if(p1==x&&p2==x)
            {vis[x]=1;que.push(node(X2[x],Y1[x],x));}
        else
        {
            p1=Y[X1[x]].pre(Y2[x]);
            p2=X[Y2[x]].nex(X1[x]);
            if(p1==x&&p2==x)
                {vis[x]=1;que.push(node(X1[x],Y2[x],x));}
        }
    }
    else
    {
        p1=X[Y2[x]].nex(X1[x]);
        p2=Y[X1[x]].nex(Y2[x]);
        if(p1==x&&p2==x)
            {vis[x]=1;que.push(node(X1[x],Y2[x],x));}
        else
        {
            p1=Y[X2[x]].pre(Y1[x]);
            p2=X[Y1[x]].pre(X2[x]);
            if(p1==x&&p2==x)
                {vis[x]=1;que.push(node(X2[x],Y1[x],x));}
        }
    }
}
void find(int x,int y)
{
    for(int i=0,t;i<4;i++)
    {
        t=move(x,y,i);
        if(t)free(t);
    }
}
char get(int x1,int y1,int x2,int y2)
{return x1==x2 ? (y1<y2 ? 'R':'L') : (x1<x2 ? 'D':'U');}
int main()
{
    //freopen("tt.in","r",stdin);
    scanf("%d%d%d",&r,&c,&n);bod=max(r,c);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d%d",&X1[i],&Y1[i],&X2[i],&Y2[i]);
        if(X1[i]>X2[i]||(X1[i]==X2[i]&&Y1[i]>Y2[i]))
            swap(X1[i],X2[i]),swap(Y1[i],Y2[i]);
    }
    init();
    scanf("%d",&m);
    for(int i=1,x,y,d1,d2,p1,p2;i<=m;i++)
    {
        scanf("%d%d%s%s",&x,&y,s1+1,s2+1);
        d1=decode(s1[1]);d2=decode(s2[1]);
        if(!poss(x,y))
        {   
            p1=move(x,y,d1);
            p2=move(x,y,d2);
            if(p1&&p1==p2)
                {del(p1);ans++;}
        }
    }
    printf("%d\n",ans);
    init();
    for(int i=1;i<=n;i++)
        free(i);
    while(!que.empty())
    {
        node t=que.front();que.pop();
        st[++top]=t;
        del(t.pos);
        find(X1[t.pos],Y1[t.pos]);
        find(X2[t.pos],Y2[t.pos]);
    }
    printf("%d\n",top);
    for(int i=1;i<=top;i++)
    {
        node t=st[i];
        printf("%d %d %c %c\n",t.x,t.y,
        get(t.x,t.y,X1[t.pos],Y1[t.pos]),
        get(t.x,t.y,X2[t.pos],Y2[t.pos]));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值