【題目描述】
BZOJ1018 | SHOI2008-堵塞的交通traffic
有一天,由于某種穿越現象作用,你來到了傳說中的小人國。小人國的布局非常奇特,整個國家的交通系統可
以被看成是一個2行C列的矩形網格,網格上的每個點代表一個城市,相鄰的城市之間有一條道路,所以總共有2C個
城市和3C-2條道路。 小人國的交通狀況非常槽糕。有的時候由于交通堵塞,兩座城市之間的道路會變得不連通,
直到擁堵解決,道路才會恢復暢通。初來咋到的你決心毛遂自薦到交通部某份差事,部長聽說你來自一個科技高度
發達的世界,喜出望外地要求你編寫一個查詢應答系統,以挽救已經病入膏肓的小人國交通系統。 小人國的交通
部將提供一些交通信息給你,你的任務是根據當前的交通情況回答查詢的問題。交通信息可以分為以下幾種格式:
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
【題目分析】
啊啊啊,我終于在題解的幫助下做出這道有(e)(e)(e)意(xin)(xin)(xin)思(ren)(ren)(ren)的題啦,之前看都不想看這道題,可是沒有辦法只能耐著性子看網上的題解,可是題解我覺得他們都覺得自己講的挺詳細,可是我看完還是一臉懵逼,又不想看代碼。找來找去找了一個代碼看起來挺好看的一個博客耐著性子看完后才算是大概理解了。
題目的意思應該挺好理解,不過需要注意的是題目中說修改的城市都是相鄰的!!!我剛開始一直沒有注意這個,覺得這個題沒法做。
還是區間問題,要用萬能的線段樹解決的話,主要的問題是維護什么,不同于一般的線段樹問題大都是一維的,這個問題是二維的,雖然只有兩行,但是顯然不是以前簡單的區間就可以的。我們要維護的是矩形區間,葉子節點是一列兩行的沒有寬度的矩形,我們對于每個矩形維護四條邊和兩條對角線來記錄矩形四個點之間的連通性關系。但是如果我們合并兩個相鄰的矩形,他們之間還有兩條邊,因此我們專門用一個數組來記錄每列之間兩條邊的關系和上下兩個城市的連通性。我們不妨記這個數組為LinkLinkLink,Link[i][0][0]Link[i][0][0]Link[i][0][0]對應第i列和i+1列第一行之間的連通性,Link[i][1][1]Link[i][1][1]Link[i][1][1]對應第i列和i+1列第二行之間的連通性,Link[i][0][1]Link[i][0][1]Link[i][0][1]對應第i列第一行與第二行之間的連通性。
然后我們用線段樹維護區間的方法維護整個區間,修改兩個城市之間的關系的時候先修改Link數組,然后根據Link數組單點修改。對于每次查詢操作,我們分別得到[1,c1],[c1,c2],[c2,n][1,c1],[c1,c2],[c2,n][1,c1],[c1,c2],[c2,n]三個區間的矩形(用一個區間查詢),然后根據這三個區間進行操作。
具體的看代碼吧,嘿嘿嘿(露出了善(xie)(xie)(xie)良(e)(e)(e))的微笑。
照著大佬的博客敲都wa了四發,嗚嗚嗚。線段樹忘記開區間*4了,然后還有一個數字寫錯了。
【參考博客】
傳送門
【AC代碼】
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<climits>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std
;typedef long long ll
;
const int INF
=0x3f3f3f3f;
const int MAXN
=1e5+5;
struct node
{int a1
,a2
,b1
,b2
,c1
,c2
;void init(){a1
=a2
=b1
=b2
=c1
=c2
=0;}
}mp
[MAXN
<<2];
int Link
[MAXN
][2][2];
int n
; char cmd
[10];
int r1
,c1
,r2
,c2
;node
PushUp(node a
,node b
,int mid
)
{node c
;if(a
.a1
|| (a
.b1
&&Link
[mid
][0][0]&&b
.a1
&&Link
[mid
][1][1]&&a
.b2
))c
.a1
=1;else c
.a1
=0;if(b
.a2
|| (b
.b1
&&Link
[mid
][0][0]&&a
.a2
&&Link
[mid
][1][1]&&b
.b2
))c
.a2
=1;elsec
.a2
=0;if((a
.b1
&&Link
[mid
][0][0]&&b
.b1
) || (a
.c1
&&Link
[mid
][1][1]&&b
.c2
))c
.b1
=1;elsec
.b1
=0;if((a
.b2
&&Link
[mid
][1][1]&&b
.b2
) || (a
.c2
&&Link
[mid
][0][0]&&b
.c1
))c
.b2
=1;elsec
.b2
=0;if((a
.b1
&&Link
[mid
][0][0]&&b
.c1
) || (b
.b2
&&Link
[mid
][1][1]&&a
.c1
))c
.c1
=1;else c
.c1
=0;if((a
.b2
&&Link
[mid
][1][1]&&b
.c2
) || (b
.b1
&&Link
[mid
][0][0]&&a
.c2
))c
.c2
=1;else c
.c2
=0;return c
;
}void build(int k
,int l
,int r
)
{mp
[k
].init();if(l
==r
){mp
[k
].b1
=mp
[k
].b2
=1;return;}int mid
=(l
+r
)>>1;build(k
<<1,l
,mid
); build(k
<<1|1,mid
+1,r
);
}void Update(int k
,int l
,int r
,int x
)
{if(l
==r
&& l
==x
){mp
[k
].b1
=mp
[k
].b2
=1;mp
[k
].a1
=mp
[k
].a2
=mp
[k
].c1
=mp
[k
].c2
=Link
[x
][0][1];return;}int mid
=(l
+r
)>>1;if(x
<=mid
) Update(k
<<1,l
,mid
,x
);else Update(k
<<1|1,mid
+1,r
,x
);mp
[k
]=PushUp(mp
[k
<<1],mp
[k
<<1|1],mid
);
}void Change(int x
)
{if(c1
==c2
){Link
[c1
][0][1]=x
;Update(1,1,n
,c1
);}else{int c
=min(c1
,c2
);Link
[c
][r1
][r1
]=x
;Update(1,1,n
,c
);}
}node
Query(int k
,int l
,int r
,int L
,int R
)
{if(l
>=L
&& r
<=R
){return mp
[k
];}int mid
=(l
+r
)>>1;node ret
; ret
.init();if(R
<=mid
) return Query(k
<<1,l
,mid
,L
,R
);else if(L
>mid
) return Query(k
<<1|1,mid
+1,r
,L
,R
);else return PushUp(Query(k
<<1,l
,mid
,L
,mid
),Query(k
<<1|1,mid
+1,r
,mid
+1,R
),mid
);
}void Ask()
{if(c1
>c2
){swap(c1
,c2
); swap(r1
,r2
);}node l
=Query(1,1,n
,1,c1
);node mid
=Query(1,1,n
,c1
,c2
);node r
=Query(1,1,n
,c2
,n
);if(r1
==r2
){if(r1
==0){if(mid
.b1
|| (l
.a2
&&mid
.c2
) || (r
.a1
&&mid
.c1
) || (l
.a2
&&mid
.b2
&&r
.a1
)){printf("Y");}else{printf("N");}}else if(r1
==1){if(mid
.b2
|| (l
.a2
&&mid
.c1
) || (r
.a1
&&mid
.c2
) || (l
.a2
&&mid
.b1
&&r
.a1
)){printf("Y");}else{printf("N");}}}else{if(r1
==0){if(mid
.c1
|| (l
.a2
&&mid
.b2
) || (r
.a1
&&mid
.b1
) || (l
.a2
&&mid
.c2
&&r
.a1
)){printf("Y");}else{printf("N");}}else if(r1
==1){if(mid
.c2
|| (l
.a2
&&mid
.b1
) || (r
.a1
&&mid
.b2
) || (l
.a2
&&mid
.c1
&&r
.a1
)){printf("Y");}else{printf("N");}}}printf("\n");
}int main()
{scanf("%d",&n
);build(1,1,n
);while(~scanf("%s",cmd
) && cmd
[0]!='E'){scanf("%d%d%d%d",&r1
,&c1
,&r2
,&c2
);r1
--; r2
--;if(cmd
[0]=='O'){Change(1);}else if(cmd
[0]=='C'){Change(0);}else{Ask();}}return 0;
}
總結
以上是生活随笔為你收集整理的BZOJ1018 | SHOI2008-堵塞的交通traffic——线段树维护区间连通性+细节的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。