CF遇难帖
1734D Slime Escape
题意:一开始你在\(k\)的位置并且有初始生命值,要走到\(1\)或者\(n\),每走一步可能掉血也可能加血,问是否能走出去
思路:以向右走为例,算出从\(k+1\)一直到哪个位置能使自己血量之和增加,记这个位置为\(r\),并且计算出从\(k+1\)~\(r\)至少要有多少生命值才能走过来,重复上述操作
将所有地块分割完后,如果自身血量大于相邻的块所需要的生命值的话,肯定就走过去,因为自身血量总会得到增加,另外,如果合并了一些块之后能直接莽到终点,便直接输出即可
A Wide, Wide Graph
显然的结论是当一个\(k\)大到对于某个点来说没有与之距离大于等于\(k\)的点的话,这个点会被孤立,否则会与其它未孤立的点形成一个连通块。
个人思路:一开始以为是换根\(dp\),处理出以每个节点为根的最大深度,后面觉得麻烦就没做了,感觉是可行的。
题解:随意从一个点\(dfs\),找到深度最深的点\(l\)(如果有多个则随意选一个),在以\(l\)为起点\(dfs\)找到最深的点\(r\)(则\(l->r\)为树的直径),处理出每个点到\(l,r\)较长的那个距离,统计答案即可。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int nxt,to;
}edge[N<<1];
int T=1,n,m,ecnt;
int dep[N],head[N];
inline int Read()
{
char ch=getchar();bool f=0;int x=0;
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;
for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
if(f==1)x=-x;return x;
}
void Add(int u,int v)
{
edge[++ecnt]=(Edge){head[u],v};
head[u]=ecnt;
}
void Dfs(int u,int fa)
{
dep[u]=dep[fa]+1;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==fa)
continue;
Dfs(v,u);
}
}
int d1[N],ans[N];
bool Solve()
{
//freopen("test.in","r",stdin);
n=Read();
for(int i=1;i<n;++i)
{
int u=Read(),v=Read();
Add(u,v);
Add(v,u);
}
dep[0]=-1;
Dfs(1,0);
int l=0,r=0,mx=0;
for(int i=1;i<=n;++i)
if(dep[i]>mx)
mx=dep[i],l=i;
dep[0]=-1;
Dfs(l,0);mx=0;
for(int i=1;i<=n;++i)
{
d1[i]=dep[i];
if(dep[i]>mx)
mx=dep[i],r=i;
}
dep[0]=-1;
Dfs(r,0);
for(int i=1;i<=n;++i)
d1[i]=max(d1[i],dep[i]),ans[d1[i]+1]++;
int now=1;
for(int i=1;i<=n;++i)
{
now+=ans[i];
printf("%lld ",min(now,n));
}
printf("\n");
return true;
}
signed main()
{
//T=Read();
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
5
2 2
1
4
1 2 1
2 5 1
*/

浙公网安备 33010602011771号