把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

qzezoj 1750 国王饮水记

当然这道题可以跑最小生成树。
但是那样时间复杂度是\(O(nmα(n))\),可以被卡掉。
这里有一个跑不满\(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);
	}
}
posted @ 2020-10-05 14:41  275307894a  阅读(51)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end