• [CERC2016]机棚障碍 Hangar Hurdles(kruskal重构树+树上倍增)


    题面



    $ solution: $

    某蒟蒻的心路历程:

    这一题第一眼感觉很奇怪
    带障碍物的图,最大的集装箱?
    首先想到的就是限制我集装箱大小条件的是什么:
    如果我要在某一个点上放一个集装箱且使它最大,
    那就相当于求这一个点往外扩出去的最大正方形。
    然后考虑从一个点到与它相邻的点移动时最大的箱子,
    这不就是这两个点的最大正方形中较小的那一个吗?
    于是考虑把所有点上的最大正方形都求出来,这个n^2即可
    然后我就是要求两个点之间所有路径上的最小的那个最大正方形了
    仔细一想,嗯?,这不就是货车运输吗?难道我要切题了?
    但毕竟被虐的太多了,还是理智的看一遍吧
    哇,边数最多可以达到1000000条,我记得火车运输范围只有10000来着?
    我靠,要凉啊,算了直接写暴力得了!(然而,……..)

    这一道题,仔细审一下题面我们可以发现:在每一个位置上箱子都有一个初始大小,而它如果要移动到与它中心相邻的某一个点上,他的大小又会受到它要移动到的那个点。所以我们可以先跑一遍BFS来求出没一点的初始最大正方形(这个我们可以反过来,从障碍物出发向四周扩展,每个点只会进队一次,复杂度完全可以接受)。然后我们对任何一对相邻的点连边,边权即为两个中最大正方形较小的那一个。这样我们如果要求两条点可以运输的最大正方形,就是求他们之间所有路径中最小权值最大的那一个,而这不就是货车运输吗????(好吧,其实LCA十分容易被卡,所以建议用树链剖分)



    $ code: $

    #include<iostream>
    #include<cstdio>
    #include<iomanip>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<ctime>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    
    #define ll long long
    #define db double
    #define inf 0x7fffffff
    #define rg register int
    
    using namespace std;
    
    struct su{
        int x,y,v;
        bool operator <(su x){return v>x.v;}
    }b[2000005];
    
    struct pi{
        int x,y,v;
    }t[2000005];
    
    struct ya{
        int to,v,next;
    }d[2000005];
    
    int n,m,tt,top,ttt,xx,yy,ans;
    int a[1000005];
    int tou[1000005];
    int s[1005][1005];
    bool k[1005][1005];
    char c[1005];
    bool vis[1000005];
    int dp[1000005];
    int lg[1000005];
    int f[1000005][20];
    int st[1000005][20];
    
    inline int qr(){
        char ch;
        while((ch=getchar())<'0'||ch>'9');
        int res=ch^48;
        while((ch=getchar())>='0'&&ch<='9')
            res=res*10+(ch^48);
        return res;
    }
    
    inline int max(int x,int y){return x<y?y:x;}
    inline int min(int x,int y){return x<y?x:y;}
    inline int minn(int x,int y,int z){return x<y?(x<z?x:z):(y<z?y:z);}
    inline int get(int x){return x==a[x]?x:a[x]=get(a[x]);}
    
    inline void qw(int x){
        printf("(%d %d)",(x%n==0?x/n-1:x/n),(x%n==0?n:x%n));
    }
    
    inline void yu(){
        int i=0,x,y,v;
        while(++i<=tt){
            x=t[i].x;y=t[i].y;v=t[i].v;
            if(!k[x+1][y+1]&&x+1<=n&&y+1<=n) s[x+1][y+1]=v, k[x+1][y+1]=1, t[++tt]=pi{x+1,y+1,v+1};
            if(!k[x+1][y]&&x+1<=n&&y<=n)     s[x+1][y]=v,   k[x+1][y]=1,   t[++tt]=pi{x+1,y,v+1};
            if(!k[x+1][y-1]&&x+1<=n&&0<y-1)  s[x+1][y-1]=v, k[x+1][y-1]=1, t[++tt]=pi{x+1,y-1,v+1};
            if(!k[x][y+1]&&0<x&&y+1<=n)      s[x][y+1]=v,   k[x][y+1]=1,   t[++tt]=pi{x,y+1,v+1};
            if(!k[x][y-1]&&0<x&&0<y-1)       s[x][y-1]=v,   k[x][y-1]=1,   t[++tt]=pi{x,y-1,v+1};
            if(!k[x-1][y+1]&&0<x-1&&y+1<=n)  s[x-1][y+1]=v, k[x-1][y+1]=1, t[++tt]=pi{x-1,y+1,v+1};
            if(!k[x-1][y]&&0<x-1&&y<=n)      s[x-1][y]=v,   k[x-1][y]=1,   t[++tt]=pi{x-1,y,v+1};
            if(!k[x-1][y-1]&&0<x-1&&0<y-1)   s[x-1][y-1]=v, k[x-1][y-1]=1, t[++tt]=pi{x-1,y-1,v+1};
        }
    }
    
    inline bool dfs(int i,int fa,int dp){
        for(rg j=tou[i];j;j=d[j].next){
            int to=d[j].to;
            if(to==fa)continue;
            //qw(i);cout<<"=>";qw(to);;
            if(to==yy){
                ans=min(dp,d[j].v);
                return 1;
            }
            if(dfs(to,i,min(dp,d[j].v)))return 1;
        }return 0;
    }
    
    inline void lca(int x,int dep){
        dp[x]=dep; vis[x]=1;
        for(rg i=0;i<19;++i)
            f[x][i+1]=f[f[x][i]][i];
        for(rg i=0;i<19;++i)
            st[x][i+1]=min(st[x][i],st[f[x][i]][i]);
        for(rg i=tou[x];i;i=d[i].next){
            int to=d[i].to;
            if(to==x||vis[to])continue;
            f[to][0]=x;
            st[to][0]=d[i].v;
            lca(to,dep+1);
        }
    }
    
    inline int find(int x,int y){
        if(dp[x]<dp[y])swap(x,y);
        ans=100001;
        for(rg i=19;i>=0;--i){
            if(dp[f[x][i]]>=dp[y]){
                ans=min(st[x][i],ans);
                x=f[x][i];
            }
            if(x==y)return ans;
        }
        for(rg i=19;i>=0;--i){
            if(f[x][i]!=f[y][i]){
                ans=minn(ans,st[x][i],st[y][i]);
                x=f[x][i];y=f[y][i];
            }
        }
        return minn(ans,st[x][0],st[y][0]);
    }
    
    int main(){
        //freopen("B.in","r",stdin);
        //freopen("B.out","w",stdout);
        n=qr();
        for(rg i=1;i<=n;++i){
            scanf("%s",c+1);
            for(rg j=1;j<=n;++j)
                if(c[j]!='.')k[i][j]=1,t[++tt]=pi{i,j,1};
        }
        for(rg i=0;i<=n+1;++i){
            k[i][0]=1;t[++tt]=pi{i,0,1};
            k[i][n+1]=1;t[++tt]=pi{i,n+1,1};
            k[0][i]=1;t[++tt]=pi{0,i,1};
            k[n+1][i]=1;t[++tt]=pi{n+1,i,1};
        }yu();
        for(rg i=1;i<=n;++i)
            for(rg j=1;j<n;++j)
                b[++top]=su{i*n+j-n,i*n+j+1-n,min(s[i][j],s[i][j+1])};
        for(rg i=1;i<n;++i)
            for(rg j=1;j<=n;++j)
                b[++top]=su{i*n+j-n,i*n+j,min(s[i][j],s[i+1][j])};
        sort(b+1,b+top+1);
        for(rg i=1;i<=n*n;++i)a[i]=i;
        for(rg i=1;i<=top;++i){
            if(get(b[i].x)!=get(b[i].y)){
                a[get(b[i].x)]=get(b[i].y);
                d[++ttt]=ya{b[i].y,b[i].v,tou[b[i].x]};tou[b[i].x]=ttt;
                d[++ttt]=ya{b[i].x,b[i].v,tou[b[i].y]};tou[b[i].y]=ttt;
            }
        }
        m=qr(); lca(1,1);
        for(rg i=1;i<=m;++i){
            xx=qr()*n+qr()-n; yy=qr()*n+qr()-n;
            int ans=find(xx,yy);
            printf("%d
    ",(!ans?0:ans*2-1));
        }
        return 0;
    }
    
    
    
  • 相关阅读:
    posix_memalign详细解释(转)——自定义对齐大小的内存分配函数
    dos下遍历目录和文件的代码(主要利用for命令)(转)
    Android遍历获取指定目录的文件(转)
    adb shell settings 控制安卓系统设置(转)
    Android中保存静态秘钥实践(转)
    Android 如何将Canvas上绘制的内容保存成本地图片(转)
    Nginx随笔
    虚拟内存和物理内存(转)
    glibc的几个有用的处理二进制位的内置函数(转)
    一个开发学习的网站(待验证)
  • 原文地址:https://www.cnblogs.com/812-xiao-wen/p/10479322.html
Copyright © 2020-2023  润新知