2014编程之美初赛第一场 1002 树

本文深入探讨了深度学习和大数据技术在人工智能领域的应用,涵盖了从理论基础到实际案例的全面分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:

时间限制: 4000ms
单点时限: 2000ms
内存限制: 256MB

描述

有一个N个节点的树,其中点1是根。初始点权值都是0。

一个节点的深度定义为其父节点的深度+1,。特别的,根节点的深度定义为1。

现在需要支持一系列以下操作:给节点u的子树中,深度在l和r之间的节点的权值(这里的深度依然从整个树的根节点开始计算),都加上一个数delta。

问完成所有操作后,各节点的权值是多少。


为了减少巨大输出带来的开销,假设完成所有操作后,各节点的权值是answer[1..N],请你按照如下方式计算出一个Hash值(请选择合适的数据类型,注意避免溢出的情况)。最终只需要输出这个Hash值即可。


MOD =1000000007; // 10^9 + 7

MAGIC= 12347;

Hash =0;

For i= 1 to N do

   Hash = (Hash * MAGIC + answer[i]) mod MOD;

EndFor


输入

第一行一个整数T (1 ≤ T ≤ 5),表示数据组数。

接下来是T组输入数据,测试数据之间没有空行。

每组数据格式如下:

第一行一个整数N (1 ≤ N ≤ 105),表示树的节点总数。

接下来N - 1行,每行1个数,a (1 ≤ a ≤ N),依次表示2..N节点的父亲节点的编号。

接下来一个整数Q(1 ≤ Q ≤ 105),表示操作总数。

接下来Q行,每行4个整数,u, l, r, delta (1 ≤ u ≤ N, 1 ≤ l ≤ r ≤ N, -109 ≤ delta ≤ 109),代表一次操作。


输出

对每组数据,先输出一行“Case x: ”,x表示是第几组数据,然后接这组数据答案的Hash值。


数据范围


小数据:1 ≤ N, Q ≤ 1000

大数据:1 ≤ N, Q ≤ 105


样例解释

点1的子树中有1,2,3三个节点。其中深度在2-3之间的是点2和点3。

点2的子树中有2,3两个节点。其中没有深度为1的节点。

所以,执行完所有操作之后,只有2,3两点的权值增加了1。即答案是0 1 1。再计算对应的Hash值即可。




样例输入
1
3
1
2
2
1 2 3 1
2 1 1 1
样例输出
Case 1: 12348

本质:

DFS


思路:

对每个点的操作以静态链表的形式存储到该点上,DFS的时候维护一个数组记录每个区间的起点权值,比如说[x,y]深度区间添加k,那么数组num[x]+=k,num[y+1]-=k,那么num数组的前n项和即为深度n的最终权值,DFS至该每一个点的时候,把每个点拥有的区间添加进去,然后再搜索下一层,回溯的时候再把这些区间剔除即可,具体实现可以看下代码

 

#include<stdio.h>
#include<string.h>
#define MOD 1000000007
int head[101000];
int fan[101000];
long long int ans[101000];
long long int num[101000];
struct node
{
	int x,y,next;
	long long int t;
}k[101000];
struct node2
{
	int x,next;
}sun[101000];
int m1,m2;
int max(int x,int y)
{
	return x>y?x:y;
}
int min(int x,int y)
{
	return x<y?x:y;
}
void dfs(int p,int dep,long long int tmp)
{
	int ptr;
	for(ptr=fan[p];ptr!=-1;ptr=k[ptr].next)//修改区间数组
	{
		k[ptr].x=max(k[ptr].x,dep);//修改至合理范围
		k[ptr].y=min(k[ptr].y,100000);//同上
		if(k[ptr].x>k[ptr].y)
			continue;
		num[k[ptr].x]+=k[ptr].t;
		num[k[ptr].y+1]-=k[ptr].t;
	}
	tmp+=num[dep];
	ans[p]=tmp;
	for(ptr=head[p];ptr!=-1;ptr=sun[ptr].next)//DFS下一层
		dfs(sun[ptr].x,dep+1,tmp);
	tmp-=num[dep];
	for(ptr=fan[p];ptr!=-1;ptr=k[ptr].next)//回溯
	{
		if(k[ptr].x>k[ptr].y)
			continue;
		num[k[ptr].x]-=k[ptr].t;
		num[k[ptr].y+1]+=k[ptr].t;
	}
}
int main()
{
	int I,T,i,n,fa,m,t1,t2,t3;
	long long int t4;
	scanf("%d",&T);
	for(I=1;I<=T;I++)
	{
		scanf("%d",&n);
		m1=m2=0;
		memset(head,-1,sizeof(head));
		memset(fan,-1,sizeof(fan));
		for(i=2;i<=n;i++)
		{
			scanf("%d",&fa);
			m1++;
			sun[m1].x=i;//叶子链表
			sun[m1].next=head[fa];
			head[fa]=m1;
		}
		scanf("%d",&m);
		for(i=1;i<=m;i++)
		{
			scanf("%d%d%d%lld",&t1,&t2,&t3,&t4);
			m2++;
			k[m2].x=t2;//操作链表
			k[m2].y=t3;
			k[m2].t=t4;
			k[m2].next=fan[t1];
			fan[t1]=m2;
		}
		memset(num,0,sizeof(num));
		dfs(1,1,0);
		long long int HASH=0,MAGIC=12347;
		for(i=1;i<=n;i++)
			HASH=(HASH*MAGIC+ans[i])%MOD;
		printf("Case %d: %lld\n",I,HASH);
	}
	return 0;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值