BZOJ #1999 [Noip2007]Core 树网的核
Description
设 $T=(V, E, W)$ 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称 $T$ 为树网(treenetwork),其中 $V, E$ 分别表示结点与边的集合,$W$ 表示各边长度的集合,并设 $T$ 有 $n$ 个结点。 路径:树网中任何两结点 $a,b$ 都存在唯一的一条简单路径,用 $d(a,b)$ 表示以 a,b 为端点的路径的长度,它是该路径上各边长度之和。我们称 $d(a,b)$ 为 $a,b$ 两结点间的距离。 一点 $v$ 到一条路径 $P$ 的距离为该点与 $P$ 上的最近的结点的距离:$d(v,P)=min\{d(v,u),u 为路径 P 上的结点\}$。 树网的直径:树网中最长的路径称为树网的直径。对于给定的树网 $T$,直径不一定是唯一的,但可以证明:各直径的中点(不一定恰好是某个结点,可能在某条边的内部)是唯一的,我们称该点为树网的中心。 偏心距 $ECC(F)$:树网 $T$ 中距路径 $F$ 最远的结点到路径 $F$ 的距离,即 。 任务:对于给定的树网 $T=(V, E,W)$ 和非负整数 $s$,求一个路径 $F$,它是某直径上的一段路径(该路径两端均为树网中的结点),其长度不超过 $s$(可以等于 $s$),使偏心距 $ECC(F)$ 最小。我们称这个路径为树网 $T=(V,E,W)$ 的核(Core)。必要时,$F$ 可以退化为某个结点。一般来说,在上述定义下,核不一定只有一个,但最小偏心距是唯一的。 下面的图给出了树网的一个实例。图中,$A-B$ 与 $A-C$ 是两条直径,长度均为 $20$。点 W 是树网的中心,$EF$ 边的长度为 $5$。如果指定 $s=11$,则树网的核为路径 $DEFG$(也可以取为路径 $DEF$),偏心距为 $8$。如果指定 $s=0$(或 $s=1$、$s=2$),则树网的核为结点 $F$,偏心距为 $12$。
Solution
找到一条直径,预处理好每个点的偏心距,从直径中点贪心扩散,选择长的那条边扩展直到核长度达到 $s$ 为止,最后还要更新到两端的距离。
Code
#include<bits/stdc++.h> using namespace std; inline int read(){ int ret=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();} while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar(); return ret*f; } int n,S,pre[500005],d[500005],dd[500005],bfsmax=0,bfsres,dfsmax=0,t[500005],m,p[500005]; bool v[500005]; int last[1000005],to[1000005],nextt[1000005],s[1000005],top=0; void add(int a,int b,int c){ nextt[++top]=last[a]; to[top]=b; s[top]=c; last[a]=top; } void bfs(int from){ memset(pre,0,sizeof(pre)); memset(d,0,sizeof(d)); memset(v,0,sizeof(v)); bfsmax=0; queue<int> q; q.push(from); d[from]=0; v[from]=1; while (!q.empty()){ int x=q.front(); q.pop(); for (int i=last[x];i;i=nextt[i]){ int y=to[i]; if (v[y]){ continue; } v[y]=1; d[y]=d[x]+s[i]; pre[y]=x; q.push(y); } if (d[x]>bfsmax){ bfsmax=d[x]; bfsres=x; } } } void dfs(int x){ v[x]=1; dfsmax=max(dfsmax,d[x]); for (int i=last[x];i;i=nextt[i]){ int y=to[i]; if (v[y]){ continue; } d[y]=d[x]+s[i]; dfs(y); } } int main(){ n=read();S=read(); for (int i=1;i<=n-1;i++){ int a=read(),b=read(),c=read(); add(a,b,c); add(b,a,c); } bfs(1); int a=bfsres; bfs(a); int b=bfsres; memset(d,0,sizeof(d)); memset(v,0,sizeof(v)); for (int i=b;i;i=pre[i]){ v[i]=1; } for (int i=b;i;i=pre[i]){ dfsmax=0; dfs(i); t[i]=dfsmax; p[++m]=i; dd[m]=d[i]; } reverse(p+1,p+1+m); bfs(a); for (int i=1;i<=m;i++){ dd[i]=d[p[i]]; } int l,r; for (int i=1;i<=m;i++){ if (d[p[i]]>=d[b]/2){ l=r=i; break; } } while (1){ if (dd[r]-dd[l]+min(dd[r+1]-dd[r],dd[l]-dd[l-1])>S||(l==1&&r==m)){ break; } if (dd[l]-dd[l-1]>dd[r]-dd[r+1]){ if (l>1&&dd[r]-dd[l-1]<=S){ l--; }else{ r++; } }else{ if (r<m&&dd[r+1]-dd[l]<=S){ r++; }else{ l--; } } } int maxx=0; for (int i=l;i<=r;i++){ maxx=max(maxx,t[p[i]]); } maxx=max(maxx,max(dd[m]-dd[r],dd[l]-dd[1])); cout<<maxx; }
#2936 [Poi1999]降 水
Description
Solution
从边缘开始 BFS,每次选择相邻最低的一块,更新高度并扩展
Code
#include<bits/stdc++.h> using namespace std; struct node{ int x,y,h; bool operator < (const node &a) const { return h>a.h; } }; priority_queue<node> q; int n,m,s[105][105],t[105][105],v[105][105],d[4][2]={{1,0},{-1,0},{0,1},{0,-1}},ans=0; int main(){ cin>>n>>m; for (int i=1;i<=n;i++){ for (int j=1;j<=m;j++){ cin>>s[i][j]; t[i][j]=s[i][j]; if (i==1||i==n||j==1||j==m){ q.push((node){i,j,s[i][j]}); v[i][j]=1; } } } while (!q.empty()){ node now=q.top(); q.pop(); for (int i=0;i<=3;i++){ int x=now.x+d[i][0]; int y=now.y+d[i][1]; if (v[x][y]){ continue; } if (x<=1||x>=n||y<=1||y>=m){ continue; } s[x][y]=max(s[x][y],now.h); v[x][y]=1; q.push((node){x,y,s[x][y]}); } } for (int i=1;i<=n;i++){ for (int j=1;j<=m;j++){ ans+=s[i][j]-t[i][j]; } } cout<<ans; }
#1907 树的路径覆盖
Description
Solution
贪心
Code
#include<bits/stdc++.h> using namespace std; inline int read(){ int ret=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();} while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar(); return ret*f; } int T,n,m,last[200005],to[200005],nextt[200005],v[200005],size[200005],top=0,ans=0; void add(int a,int b){ nextt[++top]=last[a]; to[top]=b; last[a]=top; } void dfs(int x,int fa){ size[x]=1; int sons=0; for (int i=last[x];i;i=nextt[i]){ if (to[i]==fa){ continue; } dfs(to[i],x); size[x]+=size[to[i]]; if (!v[to[i]]){ sons++; } } if (sons==1){ size[x]--; } if (sons>=2){ size[x]-=2; v[x]=1; } } int main(){ T=read(); while (T--){ memset(last,0,sizeof(last)); memset(to,0,sizeof(to)); memset(nextt,0,sizeof(nextt)); memset(v,0,sizeof(v)); memset(size,0,sizeof(size)); top=0; n=read(); for (int i=1;i<=n-1;i++){ int a=read(),b=read(); add(a,b); add(b,a); } dfs(1,0); cout<<size[1]<<endl; } }
#1270 [BeijingWc2008]雷涛的小猫
Description
Solution
水 DP,$f[x]$ 表示 $x$ 高度最大值,$g[x]$ 表示当前高度 $x$ 树最大值。
#include<bits/stdc++.h> using namespace std; int n,h,d,s[2005][2005],f[2005],g[2005]; int main(){ cin>>n>>h>>d; for (int i=1;i<=n;i++){ int m,x; cin>>m; while (m--){ cin>>x; s[i][x]++; } } g[h+1]=0; for (int i=h;i>=1;i--){ for (int j=1;j<=n;j++){ g[j]=max(g[j],f[min(i+d,h+1)])+s[j][i]; f[i]=max(f[i],g[j]); } } cout<<f[1]; }
|´・ω・)ノ
这个代码的插件是哪个qwq
嗯哼哼啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
把别人评论区变臭的屑,自裁,请
真的厉害enmm…