题目链接:树
-
1 3 1 2 2 1 2 3 1 2 1 1 1
样例输出
-
Case 1: 12348
描述
有一个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值即可。
本质:
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;
}