2014 ACM/ICPC Asia Regional Shanghai Online C - Tree —— 树上前缀和

2024-04-07 00:08

本文主要是介绍2014 ACM/ICPC Asia Regional Shanghai Online C - Tree —— 树上前缀和,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

This way

题意:

给你一棵树,两种操作:
1.将x到y的路径上的所有点的权值+k
2.将x到y路径上的所有边的权值+k
所有操作结束后问你所有的点权和所有的边权

题解:

这道题用树链剖分估计会T,因为它是 n l o g 2 n nlog^2n nlog2n的。
由于每次加的一定是一条链或者两条链,那么我们只需要用前缀和的思想去做即可,也就是说加点权的时候在x的位置加上k,y的位置+k,lca的位置-k,因为x和y的值合并了之后就变成2k,需要减掉一个。然后在lca的父亲位置-k。
边权的话只需要在x,y的位置+k,lca的位置-2k即可。我们将边权当做儿子节点处理,并且这是普遍解决边权存储位置的方法。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+5;
ll sum_p[N],sum_e[N],flag[N];
struct node
{int to,next;
}e[N*2];
int cnt,head[N];
void add(int x,int y)
{e[cnt].to=y;e[cnt].next=head[x];head[x]=cnt++;
}
int fa[N][25],dep[N];
void dfs(int x,int f)
{fa[x][0]=f;dep[x]=dep[f]+1;for(int i=head[x];~i;i=e[i].next){int ne=e[i].to;if(ne==f)continue;dfs(ne,x);}
}
int n,m;
void deal()
{for(int j=1;(1<<j)<=n;j++)for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
}
int lca(int x,int y){if(dep[x]<dep[y])swap(x,y);for(int i=20;i>=0;i--)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];if(x==y)return x;for(int i=20;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];return fa[x][0];
}
int xx[N],yy[N];
void dfs_p(int x,int f)
{for(int i=head[x];~i;i=e[i].next){int ne=e[i].to;if(ne==f)continue;dfs_p(ne,x);sum_p[x]+=sum_p[ne]-flag[ne];}
}
void dfs_e(int x,int f)
{for(int i=head[x];~i;i=e[i].next){int ne=e[i].to;if(ne==f)continue;dfs_e(ne,x);sum_e[x]+=sum_e[ne];}
}
int main()
{int t,cas=0;scanf("%d",&t);while(t--){int x,y;ll k;char op[10];scanf("%d%d",&n,&m);cnt=0;for(int i=1;i<=n;i++)sum_p[i]=sum_e[i]=flag[i]=0,head[i]=-1;for(int i=1;i<n;i++)scanf("%d%d",&xx[i],&yy[i]),add(xx[i],yy[i]),add(yy[i],xx[i]);dfs(1,0),deal();while(m--){scanf("%s%d%d%lld",op,&x,&y,&k);int l=lca(x,y);if(op[3]=='1')sum_p[x]+=k,sum_p[y]+=k,sum_p[l]-=k,flag[l]+=k;elsesum_e[x]+=k,sum_e[y]+=k,sum_e[l]-=2*k;}dfs_p(1,0),dfs_e(1,0);printf("Case #%d:\n",++cas);for(int i=1;i<=n;i++){printf("%lld",sum_p[i]);if(i==n)printf("\n");elseprintf(" ");}if(n==1)printf("\n");for(int i=1;i<n;i++){printf("%lld",dep[xx[i]]>dep[yy[i]]?sum_e[xx[i]]:sum_e[yy[i]]);if(i==n-1)printf("\n");elseprintf(" ");}}return 0;
}

这篇关于2014 ACM/ICPC Asia Regional Shanghai Online C - Tree —— 树上前缀和的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/881186

相关文章

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

ZOJ Monthly, August 2014小记

最近太忙太忙,只能抽时间写几道简单题。不过我倒是明白要想水平提高不看题解是最好的了。 A  我只能死找规律了,无法证明 int a[50002][2] ;vector< vector<int> > gmax , gmin ;int main(){int n , i , j , k , cmax , cmin ;while(cin>>n){/* g

2014 Multi-University Training Contest 8小记

1002 计算几何 最大的速度才可能拥有无限的面积。 最大的速度的点 求凸包, 凸包上的点( 注意不是端点 ) 才拥有无限的面积 注意 :  凸包上如果有重点则不满足。 另外最大的速度为0也不行的。 int cmp(double x){if(fabs(x) < 1e-8) return 0 ;if(x > 0) return 1 ;return -1 ;}struct poin

2014 Multi-University Training Contest 7小记

1003   数学 , 先暴力再解方程。 在b进制下是个2 , 3 位数的 大概是10000进制以上 。这部分解方程 2-10000 直接暴力 typedef long long LL ;LL n ;int ok(int b){LL m = n ;int c ;while(m){c = m % b ;if(c == 3 || c == 4 || c == 5 ||

2014 Multi-University Training Contest 6小记

1003  贪心 对于111...10....000 这样的序列,  a 为1的个数,b为0的个数,易得当 x= a / (a + b) 时 f最小。 讲串分成若干段  1..10..0   ,  1..10..0 ,  要满足x非递减 。  对于 xi > xi+1  这样的合并 即可。 const int maxn = 100008 ;struct Node{int

Regionals 2004 Asia - Beijing Argus 小根堆

点击打开链接 小根堆 import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.math.BigInteger;import java.util.StringTokeni

树(Tree)——《啊哈!算法》

树 什么是树?树是一种特殊的图,不包含回路的连通无向树。 正因为树有着“不包含回路”这个特点,所以树就被赋予了很多特性。 一棵树中的任意两个结点有且仅有唯一的一条路径连通。一棵树如果有n个结点,那么它一定恰好有n-1条边。在一棵树中加一条边将会构成一个回路。 一棵树有且只有一个根结点。 没有父结点的结点称为根结点(祖先)。没有子结点的结点称为叶结点。如果一个结点既不是根结点也不是叶

【LeetCode热题100】前缀和

这篇博客共记录了8道前缀和算法相关的题目,分别是:【模版】前缀和、【模版】二维前缀和、寻找数组的中心下标、除自身以外数组的乘积、和为K的子数组、和可被K整除的子数组、连续数组、矩阵区域和。 #include <iostream>#include <vector>using namespace std;int main() {//1. 读取数据int n = 0, q = 0;ci

226 Invert Binary Tree

//226 Invert Binary Tree//算法思路:主要使用递归算法public class Solution {public TreeNode invertTree(TreeNode root) {//1 出口 空节点if (root==null)return null;//2 递归 调用自己TreeNode left = root.left;TreeNode right = ro

前缀和 — 利用前缀信息解决子数组问题

【前缀和的核心思想是预先处理数组来快速计算任意子数组的和,基本上用于数组和序列问题。】 前缀和算法具体步骤 构造前缀和数组: 给定一个数组nums,其前缀和数组prex定义为prex[i]表示为数组nums从起始位置到第i个位置的元素累加和。构建前缀和公式: p r e x [ i ] = n u m s [ i ] ( i = = 0 ) p r e x [ i ] = p r e x