牛半仙的妹子树
题面
牛半仙有n个妹子,她们所在的位置组成一棵树,相邻两个妹子的距离为1,m个妹子具有超能力,她们会影响到其他妹子。离所有具有超能力的妹子的最短距离在[l,r]间的妹子会受到影响,会具有旪超能力。
这些具有能力的妹子共同形成了一个磁场。对于一个位置,一个具有超能力的妹子为其增加的磁场强度为妹子到这个位置的距离的平方,一个具有旪超能力的妹子为其增加的磁场强度为妹子到这个位置的距离。
现在牛半仙想知道一个位置的磁场强度有多大。
因为牛半仙对妹子们特别关心,所以他有k个询问。
解法
写了两道题了,也累了,写简单一点吧……
换根DP,理解了之后比前两道题都好写。
首先把具有旪超能力的节点找出来,这一点可以用广搜实现(毕竟是求每个点到超能力的点的最短距离,又是一棵树,完全可以用搜索做)。
然后就是换根DP的惯常操作(虽然换根DP的题我也没做几道)。
第一步,以某个点为根,求出每棵子树的dp值。由于超能力点和旪超能力点的贡献算法不同且互相独立,我们把它们分开算。
假如
超能力的点稍微复杂。假如
然后就可以计算出以1为根时所有子树的贡献情况。接下来是换根部分。
把你的父亲当成你的孩子(感觉这句话有点不太对),计算节点父亲的fa、fa1、fb、numa、numb,然后用这些值更新当前节点的这些数值即可。numa、numb的计算方式是总数减去以当前节点为根(1为根的意义下)的子树的数量,其它的就是父亲当前的值减去这个节点对于父亲贡献的值。然后dfs即可。
对于询问,由于不带修改,直接输出
复杂度
#include<cstdio>
#include<queue>
#define ll long long
//#define zczc
using namespace std;
const int N=500010;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
wh*=f;return;
}
struct edge{
int t,next;
}e[N*2];
int head[N],esum;
inline void add(int fr,int to){
esum++;
e[esum].t=to;
e[esum].next=head[fr];
head[fr]=esum;
}
int m,n,q,al,ar;
bool isa[N],isb[N];
struct node{
int num,dis;
};
queue<node>qu;
bool vis[N];
void solve1(){
int s1;
for(int i=1;i<=n;i++){
read(s1);isa[s1]=true;
qu.push((node){s1,0});
vis[s1]=true;
}
while(!qu.empty()){
node now=qu.front();qu.pop();
if(now.dis>=al&&now.dis<=ar){
isb[now.num]=true;
}
if(now.dis>ar)break;
for(int i=head[now.num];i;i=e[i].next){
if(vis[e[i].t])continue;
qu.push((node){e[i].t,now.dis+1});
vis[e[i].t]=true;
}
}
return;
}
int numa[N],numb[N];
ll fa1[N],fa2[N],fb[N];
void dfs1(int wh,int fa){
numa[wh]=isa[wh],numb[wh]=isb[wh];
for(int i=head[wh],th;i;i=e[i].next){
th=e[i].t;
if(th==fa)continue;
dfs1(th,wh);
numa[wh]+=numa[th];
numb[wh]+=numb[th];
fa1[wh]+=fa1[th]+(ll)numa[th];
fa2[wh]+=fa2[th]+2*fa1[th]+(ll)numa[th];
fb[wh]+=fb[th]+(ll)numb[th];
}
}
void dfs2(int wh,int fa){
if(fa){
int numafa=numa[1]-numa[wh];
int numbfa=numb[1]-numb[wh];
ll fbfa=fb[fa]-(fb[wh]+(ll)numb[wh]);
ll fa1fa=fa1[fa]-(fa1[wh]+(ll)numa[wh]);
ll fa2fa=fa2[fa]-(fa2[wh]+2*fa1[wh]+(ll)numa[wh]);
fb[wh]+=fbfa+numbfa;
fa1[wh]+=fa1fa+(ll)numafa;
fa2[wh]+=fa2fa+2*fa1fa+(ll)numafa;
}
for(int i=head[wh];i;i=e[i].next){
if(e[i].t==fa)continue;
dfs2(e[i].t,wh);
}
return;
}
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
int s1,s2;
read(m);read(n);read(q);read(al);read(ar);
for(int i=1;i<m;i++){
read(s1);read(s2);
add(s1,s2);add(s2,s1);
}
solve1();
dfs1(1,0);
dfs2(1,0);
while(q--){
read(s1);
printf("%lld\n",fa2[s1]+fb[s1]);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具