博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[SHOI2008]堵塞的交通traffic
阅读量:5032 次
发布时间:2019-06-12

本文共 3766 字,大约阅读时间需要 12 分钟。

题意

\(2*n\)个城市排成\(2\)\(n\)列的网格,相邻两个城市间有一条道路,初始时所有道路断开,支持以下操作:断开一条道路、连通一条道路、询问两个城市是否连通

思路

开始还以为很简单,结果是道线段树神仙题

将两行弄到一起,用一颗线段树来维护列

设当前区间为\([l,r]\)\(l1\)为左上,\(l2\)为左下,\(r1\)为右上,\(r2\)为右下,维护六个值(是否连通):

  1. \(L : (l1,l2)\),左上左下
  2. \(R : (r1,r2)\),右上右下
  3. \(U : (l1,r1)\),左上右上
  4. \(D : (l2,r2)\),左下右下
  5. \(P : (l1,r2)\),左上右下
  6. \(Q : (l2,r1)\),左下右上

pushup

全场最重要的操作,主要思路即通过两边求出的连通性以及两块中间的两条边推出整块的连通性(如果自己画图手推就会很好理解)

设上面的边为\(c1\),下面的边为\(c2\)

设左子树为\(a\),右子树为\(b\)

  1. \(L\) : 既可以从左边直接转移\((a.L)\),也可以先从上面的边跑到右边再从下面的边跑回去\((a.U->c1->b.L->c2->a.D)\)

  2. \(R\) : 类似\(L\)

  3. \(U\) : 可以从左边走\(c1\)到右边\((a.U->c1->b.U)\),也可以从左边走\(c2\)到右边\((a.P->c2->b.Q)\)

  4. \(D\) : 类似\(U\)

  5. \(P\) : 类似\(U\),选择\(c1(a.U->c1->b.P)\)或者\(c2(a.P->c2->b.D)\)

  6. \(Q\) : 类似\(P\)

modify

不同于我看过的几篇博客,对于修改操作可以直接在存道路的数组里面改,修改的这条道路会影响包含这个点的区间,所以修改之后调用\(modify\)函数递归到这个点重新进行\(pushup\)操作即可

query

询问操作即提取区间,这个操作做过几道线段树题目的都会吧

但是这里有一个问题,实际上从一个城市到另一个城市并不是一定走这个提取出的区间里面的道路,这意味着这条路径可能从区间外面绕一转之后才回来,所以我们还要提取两边的区间,用类似上面\(pushup\)的方法合并道路

Code

#include
#define N 100005using namespace std;int n;char c[10];int h[2][N],w[N];//横两排,竖排struct Node{ int l,r; bool L,R;//左上左下,右上右下 bool U,D;//左上右上,左下右下 bool P,Q;//左上右下,右上左下 }t[N<<2];template
void read(T &x){ char c;int sign=1; while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48; while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;}inline Node pushup(Node a,Node b){ int u=h[0][a.r],d=h[1][a.r]; Node ret; ret.l=a.l; ret.r=b.r; ret.L=(a.L) | (u&d&b.L&a.U&a.D); ret.R=(b.R) | (u&d&a.R&b.U&b.D); ret.U=(a.U&u&b.U) | (a.P&d&b.Q); ret.D=(a.D&d&b.D) | (a.Q&u&b.P); ret.P=(a.P&d&b.D) | (a.U&u&b.P); ret.Q=(a.Q&u&b.U) | (a.D&d&b.Q); return ret;}void build(int rt,int l,int r){ if(l==r) { t[rt].l=t[rt].r=l; t[rt].U=t[rt].D=1; return; } int mid=(l+r)>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); t[rt]=pushup(t[rt<<1],t[rt<<1|1]);}void modify(int rt,int x){ if(t[rt].l==t[rt].r) { t[rt].L=t[rt].R=w[t[rt].l]; t[rt].P=t[rt].Q=w[t[rt].l]; t[rt].U=t[rt].D=1; return; } int mid=(t[rt].l+t[rt].r)>>1; if(x<=mid) modify(rt<<1,x); else modify(rt<<1|1,x); t[rt]=pushup(t[rt<<1],t[rt<<1|1]);}Node query(int rt,int x,int y){ if(x<=t[rt].l&&t[rt].r<=y) return t[rt]; int mid=(t[rt].l+t[rt].r)>>1; if(x<=mid&&y<=mid) return query(rt<<1,x,y); if(y>mid&&x>mid) return query(rt<<1|1,x,y); Node ll=query(rt<<1,x,y),rr=query(rt<<1|1,x,y); return pushup(ll,rr);}void BOOL(bool x){ if(x) printf("Y\n"); else printf("N\n");}int main(){ read(n); build(1,1,n); while(1) { scanf("%s",c); if(c[0]=='E') break; int r1,c1,r2,c2; read(r1);read(c1); read(r2);read(c2); if(c1>c2) swap(c1,c2),swap(r1,r2); if(c[0]=='C')//断路 { if(r1==r2) { h[r1-1][c1]=0; modify(1,c1); modify(1,c2); } else { w[c1]=0; modify(1,c1); } } if(c[0]=='O')//通路 { if(r1==r2) { h[r1-1][c1]=1; modify(1,c1); modify(1,c2); //更新两头 } else { w[c1]=1; modify(1,c1); } } if(c[0]=='A')//询问 { Node q=query(1,c1,c2),ll=query(1,1,c1),rr=query(1,c2,n); if(r1==1&&r2==1) BOOL((q.U)|(ll.R&q.Q)|(ll.R&q.D&rr.L)); if(r1==1&&r2==2) BOOL((q.P)|(ll.R&q.D)|(q.U&rr.L)); if(r1==2&&r2==1) BOOL((q.Q)|(ll.R&q.U)|(q.D&rr.L)); if(r1==2&&r2==2) BOOL((q.D)|(ll.R&q.P)|(ll.R&q.U&rr.L)); } } return 0;}

转载于:https://www.cnblogs.com/Chtholly/p/11436658.html

你可能感兴趣的文章
Sam做题记录
查看>>
[bzoj] 2453 维护数列 || 单点修改分块
查看>>
IIS版本变迁
查看>>
mybatis09--自连接一对多查询
查看>>
myeclipse10添加jQuery自动提示的方法
查看>>
【eclipse jar包】在编写java代码时,为方便编程,常常会引用别人已经实现的方法,通常会封装成jar包,我们在编写时,只需引入到Eclipse中即可。...
查看>>
视频监控 封装[PlayCtrl.dll]的API
查看>>
软件工程APP进度更新
查看>>
Python 使用正则替换 re.sub
查看>>
CTF中那些脑洞大开的编码和加密
查看>>
IdentityServer流程图与相关术语
查看>>
BirdNet: a 3D Object Detection Framework from LiDAR information
查看>>
icon fonts入门
查看>>
【Django】如何按天 小时等查询统计?
查看>>
测试用例(一)
查看>>
【转】 mysql反引号的使用(防冲突)
查看>>
邮件中的样式问题
查看>>
AJAX 状态值与状态码详解
查看>>
php面向对象编程(oop)基础知识示例解释
查看>>
1.在数组中找到与给定总和的配对
查看>>