題目鏈接:
題意:
網格圖每次刪單位長度邊之後詢問邊的兩點是否仍然聯通,強制在線。
思路:
本題的強制在線體現在下一次的輸入裏只有一個是正確的輸入,哪個是取決於上一次得出的結果。
考慮如果不強制在線,可以把整個刪邊的過程反過來看,先把k次操作的刪邊都刪掉,然後倒序每一次刪邊看作加邊。如果加邊之前兩點不聯通,而加邊後兩點聯通了,說明刪掉這條邊會使這兩點不聯通。維護聯通與否可以用路徑壓縮的並查集。倒序跑一次就可以得出每次操作的答案。
可是這道題難就難在了強制在線,一旦強制在線做法就完全不同了。
首先簡單介紹一下對偶圖的概念,對偶圖是由平面圖變來的,平面圖的概念就是:圖畫在平面上,邊的交點只能爲結點的圖。對偶圖就是把邊圈起來的一個個“網格”看作結點形成的圖。就網格圖而言,網格圖裏原來交叉點當作一個結點,對偶圖裏就是把白塊當作一個結點。
如上圖中將3x3的網格外界看爲一點,每個網格看成一點,它們構成一個無向圖。
考慮刪邊什麼時候會使兩個點不連通,舉個例子,(1,2)和(2,2),當(1,2)到(2,2)的唯一橋樑是它們之間直接相連的這條線段時,刪邊會使其不連通,此時這條線段左側兩條邊和右側兩條邊每部分一定至少各刪掉了一條,0,1已經聯通了,0,2也已經聯通了。
總結歸納出當所刪邊兩側方格已經聯通的時候,刪掉這條邊將使兩點不聯通。那麼就可以將問題轉化爲網格圖的對偶圖刪邊之前兩點是否聯通。給每個網格編個號,用並查集維護是否連通,此題可解。
代碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
static const int maxn = 2250000;
static const int INF = 0x3f3f3f3f;
static const int mod = (int)1e9 + 7;
static const double eps = 1e-6;
static const double pi = acos(-1);
void redirect(){
#ifdef LOCAL
freopen("test.txt","r",stdin);
#endif
}
int fa[maxn];
int find(int x){
return fa[x] == x ? x : (fa[x] = find(fa[x]));
}
void combine(int x, int y) {
int xfa = find(x),yfa = find(y);
if(xfa != yfa) {
fa[yfa] = xfa;
}
}
void init(){
for(int i = 0;i < maxn;i++)fa[i] = i;
}
int n,a1,b1,a2,b2;
char c1,c2;
int solve(int a,int b,int type){
int x,y;
if(type){
if(b == 1)x = 0,y = (a-1)*(n-1)+1;
else if(b == n)x = 0,y = a*(n-1);
else x = (a-1)*(n-1)+b-1,y = (a-1)*(n-1)+b;
}
else{
if(a == 1)x = 0,y = b;
else if(a == n)x = 0,y = (n-2)*(n-1)+b;
else x = (a-2)*(n-1)+b,y = (a-1)*(n-1)+b;
}
if(find(x) == find(y)){
puts("NIE");
return 1;
}
puts("TAK");
combine(x,y);
return 0;
}
int main(){
redirect();
init();
int k,type = 0;
scanf("%d %d",&n,&k);
for(int i = 1;i <= k;i++){
scanf("%d %d %c",&a1,&b1,&c1);
getchar();
scanf("%d %d %c",&a2,&b2,&c2);
getchar();
if(type)type = solve(a2,b2,c2=='N'?0:1);
else type = solve(a1,b1,c1=='N'?0:1);
}
return 0;
}