浅谈淀粉质
题意:给定一棵带权无根树,问是否有点对的距离为k
暴力的做法可以枚举所有点对,树上差分即可,复杂度为O(n^2logn),显然还需要优化
有一个显然的性质,对于任意两个点所夹成的路径,有两种情况:
1.经过根节点的路径
2.不经过根节点的路径
对与第一类路径,dis[u->v] = dis[u->rt] + dis[v ->rt]
对于第二类路径,我们可以求出LCA在进行讨论,但是我们可以继续递归下去,找到另一个rt,把他转化成第一类路径来讨论
不难发现,这样递归下去的复杂度是和深度有关的,所以我们要尽量的减小深度来优化复杂度,那么我们怎么办呢?
对于每一棵树,我们都有一个重心(删掉重心后剩下的子树尽可能地平衡(分出来的最大子树的size尽可能地小))
举个例子,对于这张图,深度达到了6,显然不够优秀
但是如果我们以5为根,树就会变成这样,深度变为了4:
可见根的选择是对复杂度有影响的,如果数据足够大,出题人足够毒瘤,那么影响显然还会更大
那重心要怎么着呢?我们可以利用树(mo)形(ni)DP的思想来做,即找到该节点所有的子树,找到最大的哪一棵即可,代码如下:
il void getroot(int u, int fr)
{
dp[u] = 0, size[u] = 1;
Next(i, u)
{
int v = e[i].v;
if(v == fr || vis[v]) continue;
getroot(v, u);
size[u] += size[v];
dp[u] = max(dp[u], size[v]);
}
dp[u] = max(dp[u], sum - size[u]);//还有一棵以其父亲节点为根的子树
if(dp[u] < dp[root]) root = u;
}
找到重心后,我们不断的递归,在递归过程中也要不断寻找重心来优化复杂度。
代码如下:
il void solve(int u)
{
vis[u] = pd[0] = 1, doit(u);//doit表示做一些
Next(i, u)
{
int v = e[i].v;
if(vis[v]) continue;
dp[0] = n, sum = size[v], root = 0;
getroot(v, u), solve(root);
}
}
那么doit要怎么写呢?
由于我们保证了所有的树都是第一种树(经过根节点的路径),所以我们对于每一个根,可以先预处理出每一个子节点到根的距离,这样我们就可以得到对于每一个点可能出现的距离
代码如下:
il void getdis(int u, int fr)
{
rev[++ tot] = dis[u];
Next(i, u)
{
int v = e[i].v;
if(v == fr || vis[v]) continue;
dis[v] = dis[u] + e[i].w;
getdis(v, u);
}
}
求出了所有距离以后,我们就可以合并答案了,把任意两个出现的距离凑在一起,并判断可否凑出我们需要的k即可(注意复原的时候不要用memset,不然复杂度就是O(n^2)了)
il void doit(int u)
{
int c = 0;
Next(i, u)
{
int v = e[i].v;
if(vis[v]) continue;
tot = 0, dis[v] = e[i].w, getdis(v, u);
rep(j, 1, tot) rep(k, 1, m) if(query[k] >= rev[j]) pax[k] |= pd[query[k] - rev[j]];
rep(j, 1, tot) q[++ c] = rev[j], pd[rev[j]] = 1;
}
rep(i, 1, c) pd[q[i]] = 0;
}
所有代码如下:
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define debug printf("Now is Line : %d\n",__LINE__)
#define file(a) freopen(#a".in","r",stdin);freopen(#a".out","w",stdout)
//#define int long long
#define inf 123456789
#define mod 1000000007
il int read()
{
re int x = 0, f = 1; re char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
return x * f;
}
#define rep(i, s, t) for(re int i = s; i <= t; ++ i)
#define drep(i, s, t) for(re int i = t; i >= s; -- i)
#define Next(i, u) for(re int i = head[u]; i; i = e[i].next)
#define lb(x) (x)&(-(x))
#define ls k * 2
#define rs k * 2 + 1
#define _ 10005
#define ___ 10000005
#define __ 105
struct edge{int v, next, w;}e[_ << 1];
int n, m, head[_], cnt, dp[_], tot, size[_], sum, root;
int dis[_], vis[_], pd[___], rev[_], pax[__], q[_], query[__];
il void add(int u, int v, int w){e[++ cnt] = (edge){v, head[u], w}, head[u] = cnt;}
il void getroot(int u, int fr)
{
dp[u] = 0, size[u] = 1;
Next(i, u)
{
int v = e[i].v;
if(v == fr || vis[v]) continue;
getroot(v, u);
size[u] += size[v];
dp[u] = max(dp[u], size[v]);
}
dp[u] = max(dp[u], sum - size[u]);
if(dp[u] < dp[root]) root = u;
}
il void getdis(int u, int fr)
{
rev[++ tot] = dis[u];
Next(i, u)
{
int v = e[i].v;
if(v == fr || vis[v]) continue;
dis[v] = dis[u] + e[i].w;
getdis(v, u);
}
}
il void doit(int u)
{
int c = 0;
Next(i, u)
{
int v = e[i].v;
if(vis[v]) continue;
tot = 0, dis[v] = e[i].w, getdis(v, u);
rep(j, 1, tot) rep(k, 1, m) if(query[k] >= rev[j]) pax[k] |= pd[query[k] - rev[j]];
rep(j, 1, tot) q[++ c] = rev[j], pd[rev[j]] = 1;
}
rep(i, 1, c) pd[q[i]] = 0;
}
il void solve(int u)
{
vis[u] = pd[0] = 1, doit(u);
Next(i, u)
{
int v = e[i].v;
if(vis[v]) continue;
dp[0] = n, sum = size[v], root = 0;
getroot(v, u), solve(root);
}
}
int main()
{
file(a);
dp[0] = sum = n = read(), m = read();
rep(i, 1, n - 1) {int u = read(), v = read(), w = read(); add(u, v, w), add(v, u, w);}
rep(i, 1, m) query[i] = read();
getroot(1, 0), solve(root);
rep(i, 1, m) puts(pax[i] ? "AYE" : "NAY");
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· [翻译] 为什么 Tracebit 用 C# 开发
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端