救救彩笔吧对空间产生畏惧了
查看原帖
救救彩笔吧对空间产生畏惧了
281497
KEBrantily楼主2020/10/7 15:26

救啊

天天MLE,空间都减小了快一倍了

甚至有的都RE与MLE同时出现

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define INF 123123123123123
#define num ch-'0'
#define N 100010
#define maxm 900010
#define NN 333333

using namespace std;

int n,m,x,y,lg[N],fa[N],tot,head[N],depth[N]; 
int z;
long long ans;
int f[N][19];//f[i][j]表示从i点向上跳2^j步到达的点
long long maxi[N][19],mini[N][19];//maxi[i][j]表示从i点向上跳2^j步能到达的最大距离,mini表示次大距离 
bool B[NN];

inline void get(int &res){
    char ch;bool flag=0;
    while(!isdigit(ch=getchar()))
        (ch=='-')&&(flag=true);
    for(res=num;isdigit(ch=getchar());res=res*10+num);
    (flag)&&(res=-res);
}

struct edge{
	int fr,to,nxt;
	int dis;
}e[NN];

inline void add(int fr,int to,int dis){
	e[++tot].to=to;
	e[tot].dis=dis;
	e[tot].fr=fr;
	e[tot].nxt=head[fr];
    head[fr]=tot;
}

inline int Getf(int x){
	if(fa[x]==x) return x;
	return fa[x]=Getf(fa[x]);
}

inline void hb(int x,int y){
	x=Getf(x);
	y=Getf(y);
	if(x!=y) fa[y]=x;
}

inline bool pd(int x,int y){
	x=Getf(x);
	y=Getf(y);
	if(x==y) return true;
	return false; 
}

inline int cmp(edge a,edge b){
	return a.dis<b.dis;
}

inline void caq(){
	for(int i=1;i<=18;++i)
		for(int j=1;j<=n;++j){
			f[j][i]=f[f[j][i-1]][i-1];//
			maxi[j][i]=max(maxi[j][i-1],maxi[f[j][i-1]][i-1]);
			mini[j][i]=max(mini[j][i-1],mini[f[j][i-1]][i-1]);
			if(maxi[j][i-1]>maxi[f[j][i-1]][i-1]) mini[j][i]=max(mini[j][i],maxi[f[j][i-1]][i-1]);
            else if(maxi[j][i-1]<maxi[f[j][i-1]][i-1]) mini[j][i]=max(mini[j][i],maxi[j][i-1]);
            //如果当前最大的找到一个更大的,那当前最大的就是次大的 
		}
}

inline void dfs(int now,int p){//此函数作为倍增求LCA的预处理函数,预处理出每个点的父亲结点和深度,以及最大和次大的初始值 
    //p是now的父亲 
	f[now][0]=p;//now往上跳一步到达p点,更新父亲结点 
//	for(long long i=1;(1<<i)<=depth[now];i++){
////	for(long long i=1;i<=18;i++){//根据数据来把2的多少次方都枚举一遍 
//		f[now][i]=f[f[now][i-1]][i-1];//从now点往上跳2^i步 也就是 往上跳2^(i-1)步后再往上跳2^(i-1)步
//	} 
	
	for(int i=head[now];i;i=e[i].nxt){
		int to=e[i].to;
		if(to==f[now][0]) continue;//如果to是now的父亲,那么他已经被访问过了,不能回溯了
	    depth[now]=depth[p]+1;//更新深度 
		//因为所有连到now点的点中,除了他的父亲点已经确定了深度和父亲结点,其他的点都没有确定,所以可以作为now点的儿子 
		maxi[to][0]=e[i].dis;
		mini[to][0]=-INF;// 
		dfs(to,now);
	}
}

inline int lca(int x,int y){
    if(depth[x]<depth[y]) swap(x,y);
//    while(depth[x]>depth[y])
//        x=f[x][lg[depth[x]-depth[y]]-1];
    for(int i=18;i>=0;--i)
		if(depth[f[x][i]]>=depth[y])
			x=f[x][i];
    if(x==y) return x;
    if(x!=y){
        for(int i=18;i>=0;--i)
            if(f[x][i]!=f[y][i]){
                x=f[x][i];
                y=f[y][i];
            }
        x=f[x][0];
    }
    return x;
}

inline int get_max(int u,int v,int maxx)
{
	long long Ans=-INF;
	for(int i=18;i>=0;--i)
	{
		if(depth[f[u][i]]>=depth[v])
		{
			if(maxx!=maxi[u][i]) Ans=max(Ans,maxi[u][i]);
			else Ans=max(Ans,mini[u][i]);
			u=f[u][i];
		}
	}
	return Ans;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
	    add(x,y,z);
//	    add(y,x,z);
	}
	
	for(int i=1;i<=n;i++){
//		lg[i]= lg[i-1]+(1<<lg[i-1]==i);//手动处理lg函数,我也看不懂,背过就完了 
		lg[i]=lg[i>>1]+1;
		fa[i]=i; 
	}
	
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=m;i++){
		if(pd(e[i].fr,e[i].to)) continue;
		hb(e[i].fr,e[i].to);
		ans+=e[i].dis;
		B[i]=true;
	}
//	cout<<ans<<"  "; 
	mini[1][0]=-INF;
	depth[1]=1;
	dfs(1,-1);
	caq();
	long long an=INF;
	
	for(long long i=1;i<=m;++i){
		if(!B[i]){
//        if(!pd(e[i].fr,e[i].to)){
			int u=e[i].fr;
			int v=e[i].to;
			long long d=e[i].dis;
			long long maxu=get_max(u,lca(u,v),d);
			long long maxv=get_max(v,lca(u,v),d);
			an=min(an,ans-max(maxu,maxv)+d);
		}
//		cout<<e[i].fr<<" "<<e[i].to<<" "<<e[i].dis<<endl;
//		cout<<lca(e[i].fr,e[i].to)<<" "<<get_max(e[i].fr,lca(e[i].fr,e[i].to),e[i].dis)<<" "<<get_max(e[i].to,lca(e[i].fr,e[i].to),e[i].dis)<<endl; 
	}

	printf("%lld",an);
	return 0;
}
2020/10/7 15:26
加载中...