\(100+90+0=190pts\)
菜死了。/kk
T1联合权值
T2Telephone Lines
T3let'danceing!
T1:模拟
乍看像tree dp,
其实只算一个简单的模拟,
很显然,当两点距离为2时,只有两种情况:
- \(u\)是\(v\)的孙子(即\(v\)是\(fa[fa[u]]\)).
- \(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:并查集或链表再加堆维护
暴力打挂。
咕了咕了