Wannafly挑战赛10 C、小H和游戏

题目链接:https://www.nowcoder.com/acm/contest/72/C

flag:思维题

*自己没有想到,一直觉得是道树分治题!其实是道查询可以为O(1)的好题!

* 利用dfs将无根树转化为有根树!  记录一个结点波及它的儿子和孙子的次数,和自己受波及的次数用sum[i][3]来记录!

*一个结点i被轰炸,危害等价于父亲的全部儿子受损一次(自己+其它同父兄弟(距离为2))sum[fa[i]][1]++、

父亲(sum[fa[i]][0]++)和i的全部儿子受损一次(距离i为1)、父亲的父亲(sum[fa[fa[i]]][0]++)和全部

孙子受损一次(sum[i][2]++)(距离为2);

*而一个点i的受损次数等于 :  sum[i][0]+sum[fa[i]][1]+sum[fa[fa[i]]][2];


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <math.h>
#define Size 750010
using namespace std;

vector <int>V[Size];

int sum[Size][3]={0};
int fa[Size];
int a,b;
void dfs(int rt){
    for(int i=0;i<V[rt].size();++i){
        if(V[rt][i]==fa[rt])continue;
        fa[V[rt][i]]=rt;
        dfs(V[rt][i]);
    }
}

int Modify(int rt){
    if(rt==1) {sum[rt][0]++;sum[rt][1]++;sum[rt][2]++;}
    else {sum[fa[fa[rt]]][0]++;sum[fa[rt]][0]++;sum[fa[rt]][1]++;sum[rt][1]++;sum[rt][2]++;}
    return (rt==1)?sum[rt][0]:(sum[rt][0]+sum[fa[rt]][1]+sum[fa[fa[rt]]][2]);
}
int main(){
    int N,Q;
    scanf("%d%d",&N,&Q);
    for(int i=1;i<N;++i){
        scanf("%d%d",&a,&b);
        V[a].push_back(b);
        V[b].push_back(a);
    }
    fa[1]=0;
    dfs(1);
    while(Q--){
        scanf("%d",&a);
        printf("%d\n",Modify(a));
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值