暑 假 队 测 Round #2

\(100+90+0=190pts\)

菜死了。/kk

T1联合权值
T2Telephone Lines
T3let'danceing!

T1:模拟

乍看像tree dp,
其实只算一个简单的模拟,
很显然,当两点距离为2时,只有两种情况:

  1. \(u\)\(v\)的孙子(即\(v\)\(fa[fa[u]]\)).
  2. \(u\)\(v\)同父亲(即\(fa[u]=fa[v]\)).

难点在于解决第二种情况,即求出任两个子节点的乘积。
容易想到\(O(n^2)\),其实只用统计子节点的和\(sum\)
结果就是\(\sum{w_i\times(sum-w_i)}\) , \(O(n)\)解决。
最大值求出两个最大的\(w_i\)即可,同样是\(O(n)\)

\(T1のCode\)

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
const int mod=10007;
int n,w[N],mx,ret,ans;
int tot,pre[N],now[N],to[N];
void add(int x,int y){
	pre[++tot]=now[x];
	to[tot]=y;now[x]=tot;
}
void dfs(int u,int fa){
	int sum=0;
	for(int i=now[u];i;i=pre[i]){
		int v=to[i];
		if(v==fa)continue;
		sum+=w[v];
		ans=(ans+w[v]*w[fa]*2)%mod;
		mx=max(mx,w[v]*w[fa]);
		dfs(v,u);
	}
	int cd=0,zd=0,tmp;
	for(int i=now[u];i;i=pre[i]){
		int v=to[i];
		if(v==fa)continue;
		if(w[v]>=zd){
			tmp=zd;
			zd=w[v];
			cd=tmp;
		}
		else cd=max(cd,w[v]);
		ans=(ans+((sum-w[v])%mod*w[v])%mod)%mod;
	}
	mx=max(mx,cd*zd);
}
int main(){
	//freopen("quan.in","r",stdin);
	//freopen("quan.out","w",stdout);
	scanf("%d",&n);
	for(int i=1,u,v;i<n;i++){
		scanf("%d%d",&u,&v);
		add(u,v);add(v,u);
	}
	for(int i=1;i<=n;i++)
		scanf("%d",&w[i]);
	dfs(1,0);
	printf("%d %d",mx,ans);
	return 0;
}

T2:二分答案+最短路

最大值最小,那当然就是二分答案!

跑最短路来\(check\),大于检验值\(x\)边权为\(1\),反之为\(0\).

因为免费\(k\)条,所以判断\(dis[n]\)是否不大于\(k\)就行了。

测试时\(l=0\)打成\(l=1\),被卡掉\(10\)分。。

(dijkstra敲的不熟所以这里用了已死的spfa(((

\(T2のCode\):

#include<bits/stdc++.h>
using namespace std;
const int N=1050;
const int M=2e4+10;
int n,m,k,dis[M],l,r,ans,tot;
int pre[M],now[M],to[M],val[M];
bool vis[M],flag=false;
void add(int x,int y,int z){
	pre[++tot]=now[x];
	now[x]=tot;to[tot]=y;
	val[tot]=z;
}
bool spfa(int x){
	queue<int>q;
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0,vis[1]=1,q.push(1);
	while(!q.empty()){
		int u=q.front();q.pop();vis[u]=0;
		for(int i=now[u];i;i=pre[i]){
			int v=to[i],Orz=(val[i]>x);
			if(dis[u]+Orz<dis[v]){
				dis[v]=dis[u]+Orz;
				if(!vis[v])vis[v]=true,q.push(v);
			}
		}
	}
	return dis[n]<=k;
}
int main(){
	//freopen("maglev.in","r",stdin);
	//freopen("maglev.out","w",stdout);
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1,u,v,t;i<=m;i++){
		scanf("%d%d%d",&u,&v,&t);
		add(u,v,t);add(v,u,t);
		r=max(r,t);l=0;
	}
	while(l<=r){
		int mid=(l+r)>>1;
		if(spfa(mid)){r=mid-1;ans=mid;flag=true;}
		else l=mid+1;
	}
	if(flag)printf("%d",ans);
	else printf("%d",-1);
	return 0;
}

T3:并查集或链表再加堆维护

暴力打挂。

咕了咕了

原文地址:https://www.cnblogs.com/Xxhdjr/p/13398892.html