codeforces 682C Alyona and the Tree DFS

这个题就是在dfs的过程中记录到根的前缀和,以及前缀和的最小值

#include <cstdio>
#include <iostream>
#include <ctime>
#include <vector>
#include <cmath>
#include <map>
#include <stack>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int N=1e5+5;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
struct Edge{
  int v,w,next;
}edge[N<<1];
int head[N],tot,a[N],n;
bool del[N];
void add(int u,int v,int w){
  edge[tot].v=v;
  edge[tot].w=w;
  edge[tot].next=head[u];
  head[u]=tot++;
}
int ret;
void dfs(int u,int f,LL cur,LL mn){
   if(del[f])del[u]=true,++ret;
   else if(cur-mn>a[u])del[u]=true,++ret;
   for(int i=head[u];~i;i=edge[i].next){
      int v=edge[i].v;
      if(v==f)continue;
      dfs(v,u,cur+1ll*edge[i].w,min(cur+1ll*edge[i].w,mn));
   }
}
int main(){
   scanf("%d",&n);
   for(int i=1;i<=n;++i)scanf("%d",&a[i]);
   memset(head,-1,sizeof(head));
   for(int i=2;i<=n;++i){
    int u=i,v,w;
    scanf("%d%d",&v,&w);
    add(u,v,w);add(v,u,w);
   }
   dfs(1,0,0,0);
   printf("%d\n",ret);
   return 0;
}

时间: 2024-12-20 22:02:03

codeforces 682C Alyona and the Tree DFS的相关文章

CodeForces 682C Alyona and the Tree (树上DFS)

题意:给定一棵树,每个叶子有一个权值,每条边也有一个权值,现在让你删最少的结点,使得从任何结点出发到另一个结点的边上权值和都小于两个结点的权值. 析:很明显是DFS,不过要想找出最少的结点可能不太容易,所以我们可以先找出剩下结点最多,那么用总数减去这个就好,那么怎么找哪些结点是剩下的呢?首先要知道,如果一个结点要被删掉, 那么它的子树肯定也要被删掉,并且,要满足dist(v, u) <= a[u]才是可能留下的,那么只要dist(v, u) >a[u],就不要,所以一定要注意的是,结点的距离可

Codeforces 682C Alyona and the Tree(树形DP)

题目大概说给一棵点有权.边也有权的树.一个结点v不高兴当且仅当存在一个其子树上的结点u,使得v到u路径上的边权和大于u的权值.现在要不断地删除叶子结点使得所有结点都高兴,问最少删几个叶子结点. 一开始题目看错了,以为说的是v到u路径上的边权和小于v的权值,然后想出了个解法:从根开始DFS,找高兴的结点,递归过程中在set插入各个祖先结权值,递归返回时从set中删除,而如果set里面最小的元素小于当前结点的路径和那么这个结点就不能要直接return,另外还用到一个简单的数学原理——两个数同时加上相

CodeForces 682C Alyona and the Tree(广搜 + 技巧)

方法:从根节点开始广搜,如果遇到了应该删除的点,就再广搜删掉它的子树并标记,然后统计一下被标记的个数就是答案,所谓技巧就是从根节点开始搜索的时候,如果遇到了某个节点的距离<0,就让它是0,0可以消除负数效应,让后面的点重新参与正常删除操作,这个方法的正确性不难证明,可以自己画一下图.而且还有比较方便的方法就是,记录不被删除的点,然后n-他们就可以了. 代码如下: #include<iostream> #include<cstdio> #include<cstring&g

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统计答案(统

Codeforces 29D Ant on the Tree 树的遍历 dfs序

题目链接:点击打开链接 题意: 给定n个节点的树 1为根 则此时叶子节点已经确定 最后一行给出叶子节点的顺序 目标: 遍历树并输出路径,要求遍历叶子节点时按照给定叶子节点的先后顺序访问. 思路: 给每个节点加一个优先级. 把最后一个叶子节点到父节点的路径上的点优先级改为1 把倒数第二个叶子节点到父节点的路径上的点优先级改为2 如此每个点就有一个优先级,每个访问儿子节点时先访问优先级大的即可 对于无解的判断:得到的欧拉序列不满足输入的叶子节点顺序即是无解. #include <cstdio> #

CodeForces 29D Ant on the Tree

给一颗树,1为根,要求遍历树上所有点,给出叶子结点的访问顺序,限制每条边至多访问两次. 首先这是一棵树,那么两点之间的路线是确定的,所以我第一遍dfs预处理出从根节点到每个叶子的路径保存,以便后面输出. 那么就按照题目要求输出叶子结点的顺序依次输出,然后从一个叶子到下一个叶子的时候,从他们的最近公共祖先转折,所以我还预处理了相邻两个叶子结点的LCA. #include <iostream> #include <cstdlib> #include <cstring> #i

codeforces 220 C. Game on Tree

题目链接 codeforces 220 C. Game on Tree 题解 对于 1节点一定要选的 发现对于每个节点,被覆盖切选中其节点的概率为祖先个数分之一,也就是深度分之一 代码 #include<cstdio> #include<algorithm> const int maxn = 1000007; struct node { int u,v,next; } edge[maxn << 1] ; int head[maxn],num = 0; inline vo

Codeforces 6D Lizards and Basements 2 dfs+暴力

题目链接:点击打开链接 #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #include<math.h> #include<queue> #include<string> #include<stdlib.h> #include<a

hdu 2489 Minimal Ratio Tree(dfs枚举 + 最小生成树)~~~

题目: 链接:点击打开链接 题意: 输入n个点,要求选m个点满足连接m个点的m-1条边权值和sum与点的权值和ans使得sum/ans最小,并输出所选的m个点,如果有多种情况就选第一个点最小的,如果第一个点也相同就选第二个点最小的........ 思路: 求一个图中的一颗子树,使得Sum(edge weight)/Sum(point weight)最小~ 数据量小,暴力枚举~~~~~dfs暴力枚举C(M,N)种情况. 枚举出这M个点之后,Sum(point weight)固定,进行prim或者K