BZOJ 4242 水壶

来源:互联网 发布:bdu 大数据 编辑:程序博客网 时间:2024/06/08 04:06

最小生成树+倍增

发现如果水壶是定值,那地图上肯定存在许多以建筑物为中心的联通块。并且随着水壶的增大,联通块大小也增大,有一些联通块会融合。

因此考虑把所有建筑物丢到队列搞BFS。如果两个联通块碰到了,就给这两个建筑物连上一条边。如果两个联通块代表的建筑之间已经存在一条路径可达,就不连。这样连出来是一棵树,而且也是最小生成树。

然而这样是的,有一个反例,因为对于同一个距离,队列更新有先后顺序。先更新的点距离远,后更新的点可能先碰到先更新的点导致连边错误。然后我发现只要不管三七二十一,是边直接连就行了,然后再求最小生成树即可。边数至多 O(hw4)

下午给自己的电脑装了ubuntu,用起来有点卡。。。好气

#include<cstdio>#include<algorithm>#define H 2005#define N 200005#define B 25using namespace std;namespace runzhe2000{    struct item{int x, y, belong, v;}que[H*H];    struct edge{int next, to, val;}e[N<<1];    struct pdge{int a, b, c;}pe[H*H];    bool operator < (pdge a, pdge b){return a.c < b.c;}    char s[H][H];    int h, w, p, q, head, tail, ecnt, pecnt, f[N], fa[N][B], fv[N][B], last[N], bel[H][H], val[H][H], dep[N];    int dx[4] = {0,0,1,-1}, dy[4] = {1,-1,0,0};    int find(int x){return f[x] == x ? x : f[x] = find(f[x]);}    void addedge(int a, int b, int c){e[++ecnt] = (edge){last[a], b, c}; last[a] = ecnt;}    void addedge2(int a, int b, int c){addedge(a,b,c); addedge(b,a,c);}    void addedge0(int a, int b, int c){pe[++pecnt] = (pdge){a,b,c};}    void dfs(int x)    {        dep[x] = dep[fa[x][0]] + 1;        for(int i = 1; i < B; i++) fa[x][i] = fa[fa[x][i-1]][i-1], fv[x][i] = max(fv[fa[x][i-1]][i-1], fv[x][i-1]);        for(int i = last[x]; i; i = e[i].next)        {            int y = e[i].to;            if(y != fa[x][0])             {                fa[y][0] = x;                fv[y][0] = e[i].val;                dfs(y);            }        }    }    int ask_lca(int a, int b)    {        if(dep[a] < dep[b]) swap(a, b);        for(int d = dep[a] - dep[b], i = 0; i < B; i++)            if(d & (1<<i)) a = fa[a][i];        for(int i = B-1; ~i; i--)            if(fa[a][i] != fa[b][i])                a = fa[a][i], b = fa[b][i];        return a == b ? a : fa[a][0];    }    int ask_max(int b, int a)    {        int r = 0, d = dep[a] - dep[b];        for(int i = B-1; ~i; i--)            if(d & (1<<i)) r = max(r, fv[a][i]), a = fa[a][i];        return r;    }    void main()    {        scanf("%d%d%d%d",&h,&w,&p,&q);        for(int i = 1; i <= h; i++)            scanf("%s",s[i]+1);        for(int i = 1, x, y; i <= p; i++)        {            scanf("%d%d",&x,&y);            que[tail++] = (item){x, y, i, 0};            bel[x][y] = i;        }        for(; head < tail; head++)        {            int x = que[head].x, y = que[head].y;            for(int k = 0; k < 4; k++)            {                int nx = x + dx[k], ny = y + dy[k];                if(nx < 1 || ny < 1 || nx > h || ny > w || s[nx][ny] == '#') continue;                if(bel[nx][ny] && bel[nx][ny] != bel[x][y])                    addedge0(que[head].belong, bel[nx][ny], val[nx][ny] + que[head].v);                else if(!bel[nx][ny])                {                    bel[nx][ny] = que[head].belong;                    val[nx][ny] = que[head].v + 1;                    que[tail++] = (item){nx, ny, bel[nx][ny], val[nx][ny]};                }            }        }        sort(pe+1, pe+1+pecnt);        for(int i = 1; i <= p; i++) f[i] = i;        for(int i = 1; i <= pecnt; i++)        {            int f1 = find(pe[i].a), f2 = find(pe[i].b);            if(f1 == f2) continue;            f[f1] =f2;            addedge2(pe[i].a,pe[i].b,pe[i].c);        }        for(int i = 1; i <= p; i++)            if(!fa[i][0]) dfs(i);        for(int i = 1, a, b; i <= q; i++)        {            scanf("%d%d",&a,&b);            if(find(a) != find(b))                puts("-1");            else            {                int c = ask_lca(a, b), ans = 0;                ans = max(ans, ask_max(c, a));                ans = max(ans, ask_max(c, b));                printf("%d\n",ans);            }        }    }   }int main(){    runzhe2000::main();}
0 0