bzoj4793: [CERC2016]机棚障碍 Hangar Hurdles

bzoj权限题,可以去洛谷上交


先考虑每个点最大可以放多大的箱子,这需要求出离他最近的障碍距离,
这可以从障碍开始bfs,仔细观察发现要像八个方向bfs。

原题就变成了求两点之间的路径上的最小值,这显然路径在最大瓶颈生成树上最优的。点权改成边权,边权是两点之间的最小值,然后用kurskal求出最小生成树。

然后介绍一个不用树剖的方法,用kurskal求的时候并查集按秩合并,这样可以保持最小生成树的形状,并且树高是 l o g n 2 logn^2 logn2的,求路径最小就可以直接暴力爬lca

详细可以看一下bzoj4668

#include 
#include 
#include 
#include 
using namespace std;

#define dd c=getchar()
int read() {int s=0,w=1;char c;while (dd,c>'9' || c<'0') if (c=='-') w=-1;while (c>='0' && c<='9') s=s*10+c-'0',dd;return s*w;}
#undef dd
void write(int x) {if (x<0) x=-x,putchar('-');if (x>=10) write(x/10);putchar(x%10|'0');}
void wln(int x) {write(x);puts("");}

const int N=1005;
const int mx[8]={1,1,1,-1,-1,-1,0,0},my[8]={1,0,-1,1,0,-1,1,-1};

struct edge {
    int u,v,w;
    bool operator <(edge b) const {
        return w>b.w;
    }
}e[N*N*2];
int n,Q,cnt;
int dis[N][N],vis[N][N],fa[N*N],W[N*N],dep[N*N];
char s[N][N];


queueqx,qy;
void bfs() {
    while (!qx.empty()) {
        int x=qx.front(),y=qy.front();
        qx.pop();qy.pop();
        for (int i=0;i<8;i++) {
            int xx=x+mx[i],yy=y+my[i];
            if (xx>0 && xx<=n && yy>0 && yy<=n && !vis[xx][yy]) {
                dis[xx][yy]=dis[x][y]+1;
                vis[xx][yy]=1;
                qx.push(xx);qy.push(yy);
            }
        }
    }
}

int mk(int x,int y) {return n*(x-1)+y;}

void add(int u,int v,int w) {
    e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w;
}

int find(int x) {return x==fa[x]?x:find(fa[x]);}
int getDep(int x) {return x==fa[x]?1:getDep(fa[x])+1;}
int main() {
//	freopen("4793.in","r",stdin);
//	freopen("4793.out","w",stdout);
    n=read();
    for (int i=1;i<=n;i++) scanf("%s",s[i]+1);
    
    memset(dis,60,sizeof dis);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++) if (s[i][j]=='#') qx.push(i),qy.push(j),dis[i][j]=0,vis[i][j]=1;
    bfs();
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++) {
            dis[i][j]=min(dis[i][j], min(min(i ,j), min(n-i+1, n-j+1)));
            if (dis[i][j]) dis[i][j]=(dis[i][j]-1)*2+1;
        }
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++) {
            if (i1;i++) {
        u=find(e[i].u),v=find(e[i].v);
        if (u==v) continue;
        num--;
        if (dep[u]

你可能感兴趣的:(并查集,最小生成树)