[SHOI2008]堵塞的交通traffic

来源:互联网 发布:淘宝客户端怎么改差评 编辑:程序博客网 时间:2024/06/11 02:01

Description
有一天,由于某种穿越现象作用,你来到了传说中的小人国。小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C2条道路。 小人国的交通状况非常槽糕。有的时候由于交通堵塞,两座城市之间的道路会变得不连通,直到拥堵解决,道路才会恢复畅通。初来咋到的你决心毛遂自荐到交通部某份差事,部长听说你来自一个科技高度发达的世界,喜出望外地要求你编写一个查询应答系统,以挽救已经病入膏肓的小人国交通系统。 小人国的交通部将提供一些交通信息给你,你的任务是根据当前的交通情况回答查询的问题。交通信息可以分为以下几种格式:
Close r1 c1 r2 c2:相邻的两座城市(r1,c1)(r2,c2)之间的道路被堵塞了;
Open r1 c1 r2 c2:相邻的两座城市(r1,c1)(r2,c2)之间的道路被疏通了;
Ask r1 c1 r2 c2:询问城市(r1,c1)(r2,c2)是否连通。如果存在一条路径使得这两条城市连通,则返回Y,否则返回N;

Input
第一行只有一个整数C,表示网格的列数。接下来若干行,每行为一条交通信息,以单独的一行“Exit”作为结束。我们假设在一开始所有的道路都是堵塞的。我们保证C小于等于100000,信息条数小于等于100000

Output
对于每个查询,输出一个“Y”或“N”。

Sample Input
2
Open 1 1 1 2
Open 1 2 2 2
Ask 1 1 2 2
Ask 2 1 2 2
Exit

Sample Output
Y
N

HINT
题解:JudgeOnline/upload/201604/sol(4).rar

Source

思路
首先对于一个只有一行的情况,可以很容易的用线段树维护。
但是对于两行的情况,就需要用一些奇怪的技巧了。
考虑下面这个图:
就是官方题解里的图
r1,1r2,2可以先从r1,1r2,1,再到r1,2,最后是r2,2
那么可以维护r1,1r2,1的联通性,r2,1r1,2的联通性,r1,2r2,2的联通性。
具体一点,假设有区间为:

q———r
z———v

那么需要维护qrzv这4个点两两之间的联通性。
那么更新时就通过这个更新,还有区间midmid+1的联通性(第一列和第二列)就好了。
询问就按照上面的查询方法写。

代码
其实是可以不用写这么多的,只是我写的太长了……

#include <cstdio>#include <algorithm>const int maxn=100000;struct data{  int we,xc,qr,zv,qz,rv,qv,rz;  //解释一下变量名的含义:  //将键盘上左手边的一块看成一个矩形  //就是  //qwer  //asdf  //zxcv  //把q,r,z,v看成矩形的4个顶点  //w和x看成是中间点  //e和c看成是中间点的编号+1位置的点  //连起来写的两个字符表示两个位置的联通性};struct segment_tree{  data val[(maxn<<2)+10];  inline int merge(data &d,data l,data r)  //精华部分,自己画个图就明白了  //意思是将l和r区间合并成一个区间d  {    d.qz=l.qz|(l.qr&d.we&r.qz&d.xc&l.zv);    d.rv=r.rv|(r.qr&d.we&l.rv&d.xc&r.zv);    d.qr=(l.qv&d.xc&r.rz)|(l.qr&d.we&r.qr);    d.zv=(l.zv&d.xc&r.zv)|(l.rz&d.we&r.qv);    d.qv=(l.qv&d.xc&r.zv)|(l.qr&d.we&r.qv);    d.rz=(l.zv&d.xc&r.rz)|(l.rz&d.we&r.qr);    return 0;  }  int build(int now,int left,int right)  //建树  {    if(left==right)      {        val[now].qr=val[now].zv=val[now].we=val[now].xc=1;        val[now].qz=val[now].rv=val[now].qv=val[now].rz=0;        return 0;      }    int mid=(left+right)>>1;    val[now].we=val[now].xc=0;    build(now<<1,left,mid);    build(now<<1|1,mid+1,right);    merge(val[now],val[now<<1],val[now<<1|1]);    return 0;  }  int rchange(int now,int left,int right,int pos,int cval)  //将(1,pos)这个点与(2,pos)这个点的联通性变成cval  {    if(left==right)//说明当前这个位置就是pos,直接修改      {        val[now].qz=val[now].rv=val[now].qv=val[now].rz=cval;        return 0;      }    int mid=(left+right)>>1;    if(pos<=mid)//寻找pos      {        rchange(now<<1,left,mid,pos,cval);      }    else      {        rchange(now<<1|1,mid+1,right,pos,cval);      }    merge(val[now],val[now<<1],val[now<<1|1]);//更新这个点的val    return 0;  }  int uchange(int now,int left,int right,int pos,int cval)  //将(1,pos)这个点和(1,pos+1)这个点之间的联通性修改为cval  {    int mid=(left+right)>>1;    if(mid==pos)//如果中点就是pos,直接修改w->e的值      {        val[now].we=cval;        merge(val[now],val[now<<1],val[now<<1|1]);        return 0;      }    if(pos<=mid)//寻找pos      {        uchange(now<<1,left,mid,pos,cval);      }    else      {        uchange(now<<1|1,mid+1,right,pos,cval);      }    merge(val[now],val[now<<1],val[now<<1|1]);    return 0;  }  int dchange(int now,int left,int right,int pos,int cval)  //将(2,pos)这个点和(2,pos+1)这个点的联通性修改为cval  {    int mid=(left+right)>>1;    if(mid==pos)//如果中点就是pos,那么将x->c的值修改      {        val[now].xc=cval;        merge(val[now],val[now<<1],val[now<<1|1]);        return 0;      }    if(pos<=mid)//寻找pos      {        dchange(now<<1,left,mid,pos,cval);      }    else      {        dchange(now<<1|1,mid+1,right,pos,cval);      }    merge(val[now],val[now<<1],val[now<<1|1]);//更新这个点的val    return 0;  }  data query(int now,int left,int right,int s,int t)  //询问s到t区间的联通性(用一个data表示)  {    if((s<=left)&&(right<=t))      {        return val[now];        //如果已经被完全包含,直接返回这个点的val      }    int mid=(left+right)>>1;    if(s>mid)      {        return query(now<<1|1,mid+1,right,s,t);        //如果完全包含于右区间,返回右区间的寻找结果      }    else if(t<=mid)      {        return query(now<<1,left,mid,s,t);        //如果完全含于左区间,返回左区间的寻找结果      }    else      {        data res=val[now];        merge(res,query(now<<1,left,mid,s,t),query(now<<1|1,mid+1,right,s,t));        //两个区间一定是连起来的,直接用val[now]的信息合并左边和右边        return res;      }  }};segment_tree st;int n;char ch[10];inline int read(){  int x=0,f=1;  char ch=getchar();  while((ch<'0')||(ch>'9'))    {      if(ch=='-')        {          f=-f;        }      ch=getchar();    }  while((ch>='0')&&(ch<='9'))    {      x=x*10+ch-'0';      ch=getchar();    }  return x*f;}int main(){  n=read();  st.build(1,1,n);//首先建树  while(scanf("%s",ch)!=EOF)    {      if(ch[0]=='E')        {          break;        }      int ax=read(),ay=read(),bx=read(),by=read();      if(ay>by)//保证a一定在b右侧        {          std::swap(ax,bx);          std::swap(ay,by);        }      if(ch[0]=='O')        {      //分情况讨论Open的道路          if(ay==by)            {              st.rchange(1,1,n,ay,1);            }          else if(ax==1)            {              st.uchange(1,1,n,ay,1);            }          else            {              st.dchange(1,1,n,ay,1);            }        }      else if(ch[0]=='C')        {          //分情况讨论Close的道路          if(ay==by)            {              st.rchange(1,1,n,ay,0);            }          else if(ax==1)            {              st.uchange(1,1,n,ay,0);            }          else            {              st.dchange(1,1,n,ay,0);            }        }      else        {          data res=st.query(1,1,n,ay,by),l=st.query(1,1,n,1,ay),r=st.query(1,1,n,by,n);          //res是[ay,by]的联通性,l是[1,ay]的联通性,r是[by,n]的联通性          int ans;          //下面是分情况讨论a和b的横坐标,计算过程就是上面的          if((ax==1)&&(bx==1))            {              ans=res.qr|(l.rv&res.rz)|(r.qz&res.qv)|(l.rv&r.qz&res.zv);            }          else if((ax==1)&&(bx==2))            {              ans=res.qv|(l.rv&res.zv)|(r.qz&res.qr)|(l.rv&r.qz&res.rz);            }          else if((ax==2)&&(bx==1))            {              ans=res.rz|(l.rv&res.qr)|(r.qz&res.zv)|(l.rv&r.qz&res.qv);            }          else            {              ans=res.zv|(l.rv&res.qv)|(r.qz&res.rz)|(l.rv&r.qz&res.qr);            }          if(ans)            {              puts("Y");            }          else            {              puts("N");            }        }    }  return 0;}
阅读全文
0 0
原创粉丝点击