• 「BZOJ4242」水壶


    题目链接

    戳我

    (Solution)

    我们看到这题之后发现这题不是(n^2)把边弄出来后就跟货车运输差不多了,但是看了数据后发现(n^2)条边建不出来啊,这里就不详细的讲(kruskal)重构树了,只讲怎么建边

    所以我们要考虑怎么优化这个建边方式

    显然这里不可以用什么线段树,倍增,前后缀什么的来优化。

    所以我们应该考虑怎么减少需要边的数量。

    我们可以很容易的发现在这(n^2)条边中有些是可以不用的。

    举个栗子:

    我们三个点(x,y,z)

    (x)(y)有一条(1)的边
    (y)(z)有一条(1)的边
    (x)(z)有一条(2)的边

    可以发现(x)(z)的边没有意义,我们可以通过(x)(y)再到(z),这样子显然不会影响答案

    我们考虑怎么不建立这些无意义的边。

    可以先把每个建筑加入队列,跑(bfs).如果在拓展一个建筑的“势力范围”时发现这个点已经被“占领”了,这个点肯定在连接两个建筑的最短路径上.于是在这里给这两个建筑建边即可。

    至于实现,留作课后作业.

    然后在康康边权,这个可以用一个(vector)存,这样就不用(sort)了。但是我(sort)也过了

    (Code)

    #include<bits/stdc++.h>
    #define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
    using namespace std;
    const int N=4e5+10; 
    int read(){
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
        while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
        return f*x;
    }
    struct node1 {
    	int to,next;
    }e[1000001];
    struct node{
    	int x,y,v;
    }b[N*50];
    int res,cnt,n,m,t,pre[N],head[N],vis[N],W,H,Q,P,x,y;
    int f[N][21],dep[N],val[N],bin[101];
    int Vis[2010][2010],bj[2010][2010];
    char Map[2010][2010];
    void add(int x,int y){ e[++cnt].to=y,e[cnt].next=head[x],head[x]=cnt; }
    int find(int x){ return pre[x]==x?x:pre[x]=find(pre[x]); }
    bool cmp(const node & a , const node & b ){ return a.v<b.v; }
    void dfs(int k){
    	vis[k]=1;
    	for(int j=1;j<=20;j++)
    		f[k][j]=f[f[k][j-1]][j-1];
    	for(int i=head[k];i;i=e[i].next){
            int v=e[i].to;
    		f[v][0]=k,dep[v]=dep[k]+1;
    		dfs(v);
        }
    }
    int lca(int x,int y){
        if(dep[x]<dep[y])
            swap(x,y);
        for(int i=20;i>=0;i--)
            if(dep[x]-(1<<i)>=dep[y])
                x=f[x][i];
        if(x==y)
            return y;
        for(int i=20;i>=0;i--){
            if(f[x][i]==f[y][i]||!f[y][i]||!f[x][i])
                continue;
            x=f[x][i],y=f[y][i];
        }
        return f[x][0];
    }
    void build(){
    	res=n,sort(b+1,b+1+m,cmp);
    	for(int i=1;i<=m;i++){
    		int fx=find(b[i].x),fy=find(b[i].y);
    		if(fx!=fy)
    			val[++res]=b[i].v,pre[fx]=res,pre[fy]=res,add(res,fx),add(res,fy);
    		if(res==n*2-1)
    			break;
    	}
    }
    struct node2{
    	int id,x,y,v;
    };
    queue<node2> q;
    int fx[10]={0,0,0,-1,1};
    int fy[10]={0,1,-1,0,0};
    void bfs(){
    	for(int i=1;i<=n;i++)
    		x=read(),y=read(),q.push((node2){i,x,y,0}),Vis[x][y]=i;
    	while(!q.empty()){
    		node2 now=q.front();
    		q.pop();
    		for(int i=1;i<=4;i++){
    			int x=now.x+fx[i],y=now.y+fy[i];
    			if(x<1||y<1||x>H||y>W||Map[x][y]=='#') continue;
    			if(Vis[x][y]) b[++m].x=now.id,b[m].y=Vis[x][y],b[m].v=now.v+bj[x][y];
    			else Vis[x][y]=now.id,bj[x][y]=now.v+1,q.push((node2){now.id,x,y,now.v+1});
    		}
    	}
    }
    int main(){
    	bin[1]=0,H=read(),W=read(),n=read(),Q=read();
    	for(int i=1;i<=H;i++)
    		scanf("%s",Map[i]+1);
    	for(int i=1;i<=n*2;i++) pre[i]=i;
    	for(int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
    	bfs();
    	build();
    	for(int i=1;i<=n;i++)
    		if(!vis[i])
    			dfs(find(i));
    	while(Q--){
    		int x=read(),y=read(),p=lca(x,y);
    		if(p==0)
    			cout<<"-1
    ";
    		else
    			cout<<val[p]<<endl;
    	}
    }
    
  • 相关阅读:
    第 6 章 存储
    第 6 章 存储
    第 6 章 存储
    第 6 章 存储
    第 6 章 存储
    vba:csv文件批量转换为xls的宏
    MySQL安装教程 推荐5.xx版本
    Cover Letter Draft for Application
    团队角色自测问卷答案
    联想Global future leader program面试
  • 原文地址:https://www.cnblogs.com/hbxblog/p/11765892.html
Copyright © 2020-2023  润新知