Codeforces Round #381 (Div. 2) 补一道很经典的一定要记住的题

因为要期末考试了,大三的专业课还是很多的,很多大作业都要补,然后还要忙着考试,加上还有很多烦心事,很长一段时间没有刷题了,前几天做了做cf,发现变菜了很多。

主要这一场的D题, 是一场GYM的原题:http://codeforces.com/gym/101147/problem/J
还记得这道题特意问qqqq问要了代码学习了一下,这一次又碰到了,就想起上一次我没有记录,QAQ, 对 倍增法的感悟又深了一点:

题意,给一颗树,每个节点有个a值
问 每一个节点控制u 几个子节点v
控制:
v在u的子树中,而且a[v] > dis(u,v) ,则u控制v

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<vector>
const double PI = acos(-1.0);
const double e = exp(1.0);
#define ll __int64
using namespace std;
#define N 500005

vector<pair<int,ll> >G[N];

int ans[N];
ll x[N];

int fa[N][30];
ll dist[N][25];   // 数组不要开20啊,天老爷
int flag[N];
void dfs(int u,int pre){
    for(int i=1;i<=20;i++){
        fa[u][i]=fa[ fa[u][i-1] ][i-1];
        dist[u][i]=dist[u][i-1] + dist[ fa[u][i-1] ][i-1];
    }
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i].first;
        ll d=G[u][i].second;
        if(v==pre) continue;
        fa[v][0]=u;
        dist[v][0]=d;
        dfs(v,u);  //必须先更新fa和dist ,然后再dfs
    }
}
void dfs2(int u){
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i].first;
        if(v==fa[u][0]) continue;
        dfs2(v);
        flag[u]+=flag[v];
    }
}
int main(){
    //freopen("1.txt","r",stdin);
        memset(flag,0,sizeof(flag));
        memset(dist,0,sizeof(dist));
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&x[i]);
            G[i].clear();
        }
        for(int i=1;i<n;i++){
            int u,v;
            ll d ;
            scanf("%d %I64d",&u,&d);
            v=i+1;
            G[v].push_back(make_pair(u,d));
            G[u].push_back(make_pair(v,d));
        }
        fa[1][0]=0;
        dist[1][0]=1e9;
        dfs(1,0);
        for(int i=1;i<=n;i++){  //每个点的对上方的贡献值都加上去
            int cnt=i;
            flag[fa[cnt][0]]++;
            for(int j=20;j>=0;j--){   //?为什么20不行  19行?
                if(x[i]>=dist[cnt][j]){
//                      printf("i=%d j=%d cnt=%d  x=%d dist=%d\n",i,j,cnt,x[i],dist[cnt][j]);
                    x[i]-=dist[cnt][j];
//                  flag[ fa[cnt][j] ]++;  这里并不需要加,我们用dfs即可
                    cnt=fa[cnt][j];
                }
            }
            flag[fa[cnt][0]]--;   //这个处理 真的是 好巧妙啊,当成一个区间 [l,r]  l+1,由于dfs回溯  11111...r] flag[r+1]--,将不可到达的减去
        }
        dfs2(1);
        printf("%d",flag[1]);
        for(int i=2;i<=n;i++)
            printf(" %d",flag[i]);
        printf("\n");


}

C
真的是菜啊,这种题都想不出来了
因为答案肯定是 最短的那一段区间的长度
所以我们只要循环 0.1.2.3….len-1 ,就好了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值