「BZOJ4651」「NOI2016」 网格

题目描述

跳蚤国王和蛐蛐国王在玩一个游戏。

他们在一个 n n m m 列的网格上排兵布阵。其中的 c c 个格子中 (0cnm) ( 0 ≤ c ≤ n m ) ,每个格子有一只蛐蛐,其余的格子中,每个格子有一只跳蚤。

我们称占据的格子有公共边的两只跳蚤是相邻的。

我们称两只跳蚤是连通的,当且仅当这两只跳蚤相邻,或存在另一只跳蚤与这两只跳蚤都连通。

现在,蛐蛐国王希望,将某些(零个,一个或多个)跳蚤替换成蛐蛐,使得在此之后存在至少两只跳蚤不连通。

例如:我们用图表示一只跳蚤,用图表示一只蛐蛐,那么左图描述了一个 n=4, m=4, c=2 n = 4 ,   m = 4 ,   c = 2 的情况。

「BZOJ4651」「NOI2016」 网格_第1张图片「BZOJ4651」「NOI2016」 网格_第2张图片

这种情况下蛐蛐国王可以通过将第二行第二列,和第三行第三列的两只跳蚤替换为蛐蛐,从而达成他的希望,如右图所示。并且,不存在更优的方案,但是可能存在其他替换两只跳蚤的方案。

你需要首先判断蛐蛐国王的希望能否被达成。如果能够达成,你还需要最小化被替换的跳蚤的个数。

输入格式

每个输入文件包含多组数据。
输入文件的第一行只有一个整数 T T ,表示数据的组数。
接下来依次输入 T T 组数据,每组数据的第一行包含三个整数 n,m,c n , m , c
接下来 c c 行,每行包含两个整数 x,y x , y 表示第 x x 行,第 y y 列的格子被一个蛐蛐占据。每一组数据当中,同一个蛐蛐不会被多次描述。
同一行相邻的整数之间由一个空格隔开。

输出格式

对于每一组数据依次输出一行答案。

如果这组数据中,蛐蛐国王的希望不能被达成,输出-1。否则,输出被替换的跳蚤的个数的最小值。

样例

样例输入

4
4 4 2
1 1
4 4
2 3 1
1 2
2 2 2
1 1
2 2
1 1 0

样例输出

2
1
0
-1

样例解释

第一组数据就是问题描述中的例子。

对于第二组数据,可以将第二行第二列的一只跳蚤替换为蛐蛐,从而使得存在两只跳蚤不连通,并且不存在更优的方案。

对于第三组数据,最初已经存在两只跳蚤不连通,故不需要再进行替换。

对于第四组数据,由于最多只有一只跳蚤,所以无论如何替换都不能存在两只跳蚤不连通。

数据范围与提示

对于所有的数据, 1n,m109, 0cmin(nm,105), 1xn, 1ym, 1T20 1 ≤ n , m ≤ 10 9 ,   0 ≤ c ≤ min ( n m , 10 5 ) ,   1 ≤ x ≤ n ,   1 ≤ y ≤ m ,   1 ≤ T ≤ 20

我们记 c ∑ c 为某个测试点中,其 T T 组输入数据的所有 c c 的总和,则保证 c105 ∑ c ≤ 10 5

题解

首先答案不会超过 2 2 ,因为至少有一个跳蚤所在的格子相邻的跳蚤不超过 2 2 个。

对于答案是 1 − 1 的情况,有两种情况:
1. 只有一只跳蚤。
2. 只有两只跳蚤,并且他们相邻。

图不连通的时候答案为 0 0 。 图有割点的情况答案为 1 1 (把割点便乘蛐蛐)。其他的情况答案就是 2 2
然后转化成了一张网格图让你求割点。

考虑到蛐蛐数量很少,连续 >2 > 2 行跳蚤与 2 2 行跳蚤是等价的,所以可以直接离散化,于是就能得到 84 84 分了。

但是蛐蛐有 105 10 5 次方级别,很显然不能直接离散化。

std 的思路非常妙,就是只保留每个蛐蛐周围 5×5 5 × 5 25 25 个格子,中间空出来的直接连边。于是点数是 2.5×106 2.5 × 10 6 级别的,可以通过,复杂度 O(c) O ( c )

My Code

#include 

using namespace std;
int dd;
struct node{
    int id, x, y;
    node(){}
    node(int _x, int _y){
        id = 0; x = _x; y = _y;
    }
    node(int _id, int _x, int _y){
        id = _id; x = _x; y = _y;
    }

    bool operator < (const node &b) const{
        if(dd == 0){
            if(x == b.x) return y < b.y;
            return x < b.x;
        }else{
            if(y == b.y) return x < b.x;
            return y < b.y;
        }
    }
    bool operator <= (const node &b) const{
        if(dd == 0){
            if(x == b.x) return y <= b.y;
            return x < b.x;
        }else{
            if(y == b.y) return x <= b.x;
            return y < b.y;
        }
    }
    bool operator == (const node &b) const{
        return x == b.x && y == b.y;
    }
}a[100005], b[10000005];
int n, m, c, k;
int ax[300005], ay[300005], cx, cy;


struct edge{
    int to, nxt;
}e[10000005];
int h[2500005], cnt;
void addedge(int x, int y){
    cnt++; e[cnt].to = y; e[cnt].nxt = h[x]; h[x] = cnt;
    cnt++; e[cnt].to = x; e[cnt].nxt = h[y]; h[y] = cnt;
}
int dfn[2500005], low[2500005], cut; 
void dfs(int x, int fa){
    dfn[x] = low[x] = ++dfn[0];
    int cc = 0;
    for(int i = h[x]; i; i = e[i].nxt){
        if(e[i].to == fa) continue;
        if(!dfn[e[i].to]){
            cc++; dfs(e[i].to, x);
            low[x] = min(low[x], low[e[i].to]);
            if(fa && dfn[x] <= low[e[i].to]) cut = 1;
            if(!fa && cc >= 2) cut = 1;
        }else low[x] = min(low[x], dfn[e[i].to]);
    }
}
void pre(){
    for(int i = 0; i <= k; i ++){
        h[i] = dfn[i] = low[i] = 0;
    }
    cnt = cut = 0;
}
int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d%d", &n, &m, &c); k = cx = cy = 0;
        if(c == 0){
            if(1ll * n * m <= 2) puts("-1");
            else if(n == 1 || m == 1) puts("1");
            else puts("2");
            continue;
        }
        for(int i = 1; i <= c; i ++){
            int x, y;
            scanf("%d%d", &x, &y);
            a[i].x = x; a[i].y = y;
            ax[++cx] = x; ay[++cy] = y;
            if(x > 1) ax[++cx] = x - 1, b[++k] = node(x - 1, y);
            if(x < n) ax[++cx] = x + 1, b[++k] = node(x + 1, y);
            if(y > 1) ay[++cy] = y - 1, b[++k] = node(x, y - 1);
            if(y < m) ay[++cy] = y + 1, b[++k] = node(x, y + 1);    
            if(x > 1 && y > 1) b[++k] = node(x - 1, y - 1);
            if(x > 1 && y < m) b[++k] = node(x - 1, y + 1);
            if(x < n && y > 1) b[++k] = node(x + 1, y - 1);
            if(x < n && y < m) b[++k] = node(x + 1, y + 1);
        }
        if(1ll * n * m - c < 2){
            puts("-1"); continue;
        }
        int mnx = n, mny = m, mxx = 1, mxy = 1;
        for(int i = 1; i <= cx; i ++){
            mnx = min(mnx, ax[i]);
            mxx = max(mxx, ax[i]);
        }
        for(int i = 1; i <= cy; i ++){
            mny = min(mny, ay[i]);
            mxy = max(mxy, ay[i]);
        }
        if(mnx > 1) mnx--; if(mxx < n) mxx++;
        if(mny > 1) mny--; if(mxy < m) mxy++;
        ax[++cx] = mnx; ax[++cx] = mxx;
        ay[++cy] = mny; ay[++cy] = mxy;
        sort(ax + 1, ax + cx + 1); cx = unique(ax + 1, ax + cx + 1) - ax - 1;
        sort(ay + 1, ay + cy + 1); cy = unique(ay + 1, ay + cy + 1) - ay - 1;
        for(int i = 1; i <= cx; i ++){
            b[++k] = node(ax[i], ay[1]);
            b[++k] = node(ax[i], ay[cy]);
        }
        for(int i = 1; i <= cy; i ++){
            b[++k] = node(ax[1], ay[i]);
            b[++k] = node(ax[cx], ay[i]);
        }
        sort(a + 1, a + c + 1);
        sort(b + 1, b + k + 1); k = unique(b + 1, b + k + 1) - b - 1;
        for(int i = 1; i <= c; i ++){
            a[i].x = lower_bound(ax + 1, ax + cx + 1, a[i].x) - ax;
            a[i].y = lower_bound(ay + 1, ay + cy + 1, a[i].y) - ay;
        }       
        for(int i = 1; i <= k; i ++){
            b[i].x = lower_bound(ax + 1, ax + cx + 1, b[i].x) - ax;
            b[i].y = lower_bound(ay + 1, ay + cy + 1, b[i].y) - ay;
            b[i].id = i;
        }
        pre();
        dd = 1; sort(a + 1, a + c + 1); sort(b + 1, b + k + 1);
        int cc = 0;
        for(int i = 1, t1 = 1, t2 = 1; i <= k; i ++){
            while(t1 <= c && a[t1] < b[i]) t1++;
            if(a[t1] == b[i] && t1 <= c) continue;
            cc++;
            while(t1 <= c && a[t1] <= b[i]) t1++;
            while(t2 <= k && b[t2] <= b[i]) t2++;
            if(t2 <= k && b[t2].y == b[i].y && b[t2].x > b[i].x && (t1 > c || !(b[t2] == a[t1]))) addedge(b[i].id, b[t2].id);
        }
        dd = 0; sort(a + 1, a + c + 1); sort(b + 1, b + k + 1);
        for(int i = 1, t1 = 1, t2 = 1; i <= k; i ++){
            while(t1 <= c && a[t1] < b[i]) t1++;
            if(a[t1] == b[i] && t1 <= c) continue;
            while(t1 <= c && a[t1] <= b[i]) t1++;
            while(t2 <= k && b[t2] <= b[i]) t2++;
            if(t2 <= k && b[t2].x == b[i].x && b[t2].y > b[i].y && (t1 > c || !(b[t2] == a[t1]))) addedge(b[i].id, b[t2].id);
        }
        if(cnt) dfs(e[1].to, 0);    
        if(1ll * n * m - c == 2 && dfn[0] == 2) puts("-1");
        else if(dfn[0] < cc) puts("0");
        else if(cut || dfn[0] == 2) puts("1");
        else puts("2");
    }   
    return 0;
} 

你可能感兴趣的:(bzoj)