CF739B Alyona and a tree 树上差分

 题目描述

\(Alyona有一棵有 n个节点的树。这棵树的根节点是 1。在每个节点里,Alyona写了一个正整数,在节点 i 她写了正整数a_i 。另外,她在这棵树上的每条边上写了一个正整数(不同边上可能有不同的数)。 让我们定义 dist(v,u) 作为从 v 到 u 的简单路径上的边权和。 当且仅当 u 在 v 的子树中并且 dist(v,u)<=a_u,顶点 v 控制顶点 u(v!=u) 。Alyona想在某些顶点定居。为了做到这件事,她想知道在每个节点 v 能控制几个节点。\)



对于\(u\),\(v\)两点,若\(dis(u,v)<=a[u]\),则u,v间的点都满足当前性质,即满足\(u\),\(v\)间的点都能控制\(u\)

故\(dfs\)往下扫,将\(dis(u,v)<=a[u]\)拆成\(dis[v]<=dis[u]-a[u]\)用\(vector\)存当前点的\(dis[x]\),若子树中的点的\(dis[u]-a[u]\)找到从根开始第一个满足该性质的点,则该点到\(u\)点路径中所有的点都满足要求

然后差分做,返回的时候清除节点,用子节点更新当点节点

#include <bits/stdc++.h>
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Dec(i,a,b) for(int i=(a);i>=(b);i--)
const int maxn=2e5+10;
const int k=448;
typedef long long ll;
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
inline ll readll(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
int ans[maxn];
ll dis[maxn],a[maxn];
vector<ll>val[maxn];
vector<int>G[maxn];
vector<pair<ll,int> >que;
//对于u,v两点,若dis(u,v)<=a[u],则u,v间的点都满足当前性质,即满足u,v间的点都能控制u
//故dfs往下扫,将dis(u,v)<=a[u]拆成dis[v]<=dis[u]-a[u]用vector存当前点的dis[x],若子树中的点的dis[u]-a[u]找到从根开始第一个满足该性质的点,则该点到u点路径中所有的点都满足要求
//然后差分做,返回的时候清除节点
void dfs(int x,int fa){
    ans[x]=1;
    ll t=dis[x]-a[x];
    int pos=lower_bound(que.begin(),que.end(),make_pair(t,0))-que.begin()-1;
    if(pos>=0)ans[que[pos].second]--;
    que.push_back(make_pair(dis[x],x));
    For(i,0,(int)G[x].size()-1){
        int u=G[x][i];
        if(u==fa)continue;
        dis[u]=dis[x]+val[x][i];
        dfs(u,x);
        ans[x]+=ans[u];
    }
    que.pop_back();
}
int main(){
    int n;
    n=read();
    For(i,1,n)a[i]=readll();
    int v;
    ll cost;
    For(i,2,n){
        v=read();cost=readll();
        val[i].push_back(cost);
        val[v].push_back(cost);
        G[i].push_back(v);
        G[v].push_back(i);
    }
    dfs(1,-1);
    For(i,1,n)printf("%d ",ans[i]-1);
    return 0;
}

原文地址:https://www.cnblogs.com/Nan-Cheng/p/9735294.html

时间: 2024-10-28 07:25:07

CF739B Alyona and a tree 树上差分的相关文章

Codeforces 739B Alyona and a tree (树上路径倍增及差分)

题目链接 Alyona and a tree 弄了好几个小时终于Accepted了,之后发现这个题是Div1的. 比较考验我思维的一道好题. 首先,做一遍DFS预处理出t[i][j]和d[i][j].t[i][j]表示从第i个节点到离他第2^j近的祖先,d[i][j]表示从i开始到t[i][j]的路径上的路径权值总和. 在第一次DFS的同时,对节点x进行定位(结果为dist(x, y)<=a(y))的离x最远的x的某个祖先,然后进行O(1)的差分. 第一次DFS完成后,做第二次DFS统计答案(统

CF739B Alyona and a tree

倍增+差分 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=2e5+10; #define int long long int n,a[N],f[N][21],ans[N],dis[N]; int Next[2*N],head[N],go[N*2],w[N*2],tot; inline void

【CF739B】Alyona and a tree(树上差分,二分,树形DP)

题意:给出一棵有根树,树上每个点.每条边都有一个权值. 现在给出"控制"的定义:对一个点u,设点v在其子树上,且dis(u,v)≤av,则称u控制v. 要求求出每个点控制了多少个点 n (1?≤?n?≤?2·105).  (1?≤?ai?≤?109) 1?≤?pi?≤?n, 1?≤?wi?≤?109) 思路:在学校CF有时上不去不知道为什么 对于确定的点i,计算它对哪些点有贡献 dis[i]-dis[u]<=a[i] dis[u]<=a[i]-dis[i]满足二分性 倍增枚

差分 and 树上差分

差分数组 定义 百度百科中的差分定义 //其实这完全和要讲的没关系 qwq 进去看了之后是不是觉得看不懂? 那我简单概括一下qwq 差分数组de定义:记录当前位置的数与上一位置的数的差值. 栗子 容易发现的是,\(\sum_{1}^{i}{b_i}\)即代表\(a_i\) 的值. \((\sum_{1}^{i}\) 即代表从1累加到i.) 思想 看到前面的\(\sum_{1}^{i}\) 你一定会发现这是前缀和! 那你认为这是前缀和? 的确是qwq. 实际上这并不是真正意义上的前缀和. 前缀和的

差分数组 and 树上差分

差分数组 定义 百度百科中的差分定义 //其实这完全和要讲的没关系 qwq 进去看了之后是不是觉得看不懂? 那我简单概括一下qwq 差分数组de定义:记录当前位置的数与上一位置的数的差值. 栗子 容易发现的是,\(\sum_{j=1}^{i} b_j\)即代表\(a_i\) 的值. \((\sum\) 即代表累加.) 思想 看到前面的\(\sum\) 你一定会发现这是前缀和! 那你认为这是前缀和? 的确是qwq. 实际上这并不是真正意义上的前缀和. 前缀和的思想是 根据元素与元素之间的并集关系(

poj3417 Network 树上差分+LCA

题目传送门 题目大意:给出一棵树,再给出m条非树边,先割掉一条树边,再割掉一条非树边,问有几种割法,使图变成两部分. 思路:每一条 非树边会和一部分的树边形成一个环,分三种情况: 对于那些没有形成环的树边来说,割掉这条边,就已经使图分离,然后随便割一条非树边就可以了,所以这样的边每次答案加上m. 对于那些只存在在一个环中的树边来说,割掉这条边,再割一条和他存在于同一个环中的那条非树边,也能合法,所以加一. 对于存在于多个环中的树边,无论怎样,都无法合法. 也就是此时我们将题目转化成了树上的覆盖问

Luogu4556 雨天的尾巴 树上差分、线段树合并

传送门 一个套路题-- 树上差分+线段树合并即可 注意一个细节:$pushup$的时候如果最大值为$0$一定要把最大值对应的答案也设为$0$,否则会$WA$第二个点 另外如果这道题空限变小了请不要交这份代码,因为这份代码没有卡空间... 1 #include<bits/stdc++.h> 2 #define mid ((l + r) >> 1) 3 //This code is written by Itst 4 using namespace std; 5 6 inline in

[填坑]树上差分 例题:[JLOI2014]松鼠的新家(LCA)

今天算是把LCA这个坑填上了一点点,又复习(其实是预习)了一下树上差分.其实普通的差分我还是会的,树上的嘛,也是懂原理的就是没怎么打过. 我们先来把树上差分能做到的看一下: 1.找所有路径公共覆盖的边 例题:[NOIP2015]运输计划 (然而我还没过就先不讲了) 反正就是中间有一步要求一条边被所有计划公共覆盖. 那么怎么求它呢?暴力(滚粗).我们有一个非常好的方法就是树上差分(记录tmp为差分数组) 询问操作为从叶子节点的权值向上累加到root 在一条路径u→ v,如果tmp[u]++,那么我

[hdu5593 ZYB&#39;s Tree] 树上统计

题意:给1棵N(≤500,000)个节点的树,每条边边权为1,求距离每个点距离不超过K(K≤10)的点的个数的xor和. 思路:由于K很小,可以考虑把距离作为状态的一部分,然后研究父子之间状态的联系.令ans[i][j]表示与i的距离为j的点的个数,那么ans[i][j]由两部分构成,一部分来源于子树,一部分来源于父亲,那么令f[i][j]表示从子树来的答案,g[i][j]表示从父亲来的答案,son(i)表示i的儿子,fa(i)表示i的父亲,则有: ans[i][j] = f[i][j] + g