qzezoj 1750 国王饮水记

当然这道题可以跑最小生成树。
但是那样时间复杂度是 O ( n m α ( n ) ) O(nmα(n)) O(nmα(n)),可以被卡掉。
这里有一个跑不满 O ( n m ) O(nm) O(nm)
就是每次拿到一条边,就搜索是否联通。
不连通就加上去
联通就找到最大的那条边,看看能不能替换,能换就换。
代码实现:

#include<cstdio>
#include<cstring>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,nowx,nowy,flags,flag,cur;
long long ans,nowans;
struct yyy{int to,w,z,flag;}tmp;
struct ljb{
	int head,h[100039];
	yyy f[200039];
	inline void add(int x,int y,int z){
		f[++head]=(yyy){y,z,h[x],0};
		h[x]=head;
	}
}s;
inline void dfs(int x,int last,int w){
	if(x==y) flag=w;
	if(flag) return;
	yyy tmp;
	for(cur=s.h[x];~cur;cur=tmp.z){
		tmp=s.f[cur];
		if(!tmp.flag&&tmp.to!=last)dfs(tmp.to,x,max(w,tmp.w));
	}
}
inline void dfs2(int x,int last,int w){
	if(x==y) flags=w;
	if(flags) return;
	yyy tmp;
	for(cur=s.h[x];~cur;cur=tmp.z){
		tmp=s.f[cur];
		if(!tmp.flag&&tmp.to!=last){
			if(tmp.w==flag) {nowx=tmp.to,nowy=x;}
			dfs2(tmp.to,x,max(w,tmp.w));
			if(flags){
				if(tmp.w==flag) {nowx=tmp.to,nowy=x;}
				return;
			} 
		}
	}
}
inline void dfss(int x,int last){
	nowans++;
	yyy tmp;
	for(int cur=s.h[x];~cur;cur=tmp.z){
		tmp=s.f[cur];
		if(!tmp.flag&&tmp.to!=last) dfss(tmp.to,x);
	}
}
int main(){
	freopen("1.in","r",stdin); 
	freopen("1.out","w",stdout);
	memset(s.h,-1,sizeof(s.h));
	register int i;
	scanf("%d%d",&n,&m);
	while(m--){
		scanf("%d%d%d",&x,&y,&z);
		flag=0;
		dfs(x,0,0);
		if(flag>z||!flag){
			if(!flag) {ans+=z;s.add(x,y,z);s.add(y,x,z);}
			else{
				flags=0;nowx=nowy=0;
				dfs2(x,0,0);
				cur=s.h[nowx];
				while(~cur){
					tmp=s.f[cur];
					if(tmp.to==nowy&&!tmp.flag) {s.f[cur].flag=1;break;}
					cur=tmp.z;
				}
				cur=s.h[nowy];
				while(~cur){
					tmp=s.f[cur];
					if(tmp.to==nowx&&!tmp.flag){s.f[cur].flag=1;break;} 
					cur=tmp.z;
				}
				ans+=z-flag;s.add(x,y,z);s.add(y,x,z);
			}
		}
		nowans=0;
		dfss(1,0);
		printf("%lld %lld\n",ans,nowans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值