dfs序

 青出于蓝胜于蓝(jisuanke)

 青出于蓝胜于蓝

武当派一共有 nn 人,门派内 nn 人按照武功高低进行排名,武功最高的人排名第 11,次高的人排名第 22,... 武功最低的人排名第 nn。现在我们用武功的排名来给每个人标号,除了祖师爷,每个人都有一个师父,每个人可能有多个徒弟。

我们知道,武当派人才辈出,连祖师爷的武功都只能排行到 pp。也就是说徒弟的武功是可能超过师父的,所谓的青出于蓝胜于蓝。

请你帮忙计算每个人的所有子弟(包括徒弟的徒弟,徒弟的徒弟的徒弟....)中,有多少人的武功超过了他自己。

输入格式

输入第一行两个整数 n, p(1 \le n \le 100000, 1 \le p \le n)n,p(1n100000,1pn)。

接下来 n-1n1 行,每行输入两个整数 u, v(1 \le u, v \le n)u,v(1u,vn),表示 uu 和 vv 之间存在师徒关系。

输出格式

输出一行 nn 个整数,第 ii 个整数表示武功排行为 ii 的人的子弟有多少人超过了他。

行末不要输出多余的空格。

样例输入复制
10 5
5 3
5 8
3 4
3 1
2 1
6 7
8 7
9 8
8 10
样例输出复制
0 0 2 0 4 0 1 2 0 0

其实就是查询区间(l,r]有几个。由于是从名次第一开始,所以往后的名次只要在dfs序中有值便是名次比自己高但是是自己的徒弟,如果不在同一子树上,会因为dfs序的r[i]所分开,到最后只是算dfs在(l,r]这个区间的值

#include<stdio.h>
#include<vector>
using namespace std;
const int N=1e5+5,MD=1e9+7;
int L[N],R[N],c[N];
int tot,n;
vector<int>G[N];
void dfs(int u,int fa)//处理出dfs序
{
    L[u]=++tot;
    for(auto X:G[u])if(X!=fa)dfs(X,u);
    R[u]=tot;
}
void add(int x,int val)
{
    for(int i=x; i<=n; i+=(i&-i)) c[i]+=val;
}
int Sum(int x)
{
    int ans=0;
    for(int i=x; i; i-=(i&-i)) ans+=c[i];
    return ans;
}
int main()
{
    int rt;
    scanf("%d%d",&n,&rt);
    for(int i=2,u,v; i<=n; i++)
        scanf("%d%d",&u,&v),G[u].push_back(v),G[v].push_back(u);
    tot=0;
    dfs(rt,-1);
    for(int i=1;i<n;i++)printf("%d ",Sum(R[i])-Sum(L[i])),add(L[i],1);
    printf("%d",Sum(R[n])-Sum(L[n]));
}

 

 链接:https://www.nowcoder.com/acm/contest/91/B
来源:牛客网

合约数
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

在埃森哲,员工培训是最看重的内容,最近一年,我们投入了 9.41 亿美元用于员工培训和职业发展。截至 2018 财年末,我们会在全球范围内设立 100 所互联课堂,将互动科技与创新内容有机结合起来。按岗培训,按需定制,随时随地,本土化,区域化,虚拟化的培训会让你快速取得成长。小埃希望能通过培训学习更多ACM 相关的知识,他在培训中碰到了这样一个问题,

给定一棵n个节点的树,并且根节点的编号为p,第i个节点有属性值val i, 定义F(i): 在以i为根的子树中,属性值是val i的合约数的节点个数。y 是 x 的合约数是指 y 是合数且 y 是 x 的约数。小埃想知道 对1000000007取模后的结果.

输入描述:

输入测试组数T,每组数据,输入n+1行整数,第一行为n和p,1<=n<=20000, 1<=p<=n, 接下来n-1行,每行两个整数u和v,表示u和v之间有一条边。第n+1行输入n个整数val1, val2,…, valn,其中1<=vali<=10000,1<=i<=n.

输出描述:

对于每组数据,输出一行,包含1个整数, 表示对1000000007取模后的结果

示例1

输入

2
5 4
5 3
2 5
4 2
1 3
10 4 3 10 5
3 3
1 3
2 1
1 10 1

输出

11
2

备注:

n>=10000的有20组测试数据

先预处理合数的倍数,然后就是dfs序了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MD=1e9+7;
vector<int> v[20020],d[10005];
int n,rt,vis[10005];
ll val[20020],ans,f[20020];
void dfs(int x,int pre)
{
    for(auto X:d[val[x]])f[X]=(f[X]+x)%MD;
    ans=(ans+f[val[x]])%MD;
    for(auto X:v[x])if(X!=pre)dfs(X,x);
    for(auto X:d[val[x]])f[X]=(f[X]-x+MD)%MD;
}
int main()
{
    for(int i=2; i<=10000; i++)
        if(!vis[i])for(int j=i+i; j<=10000; j+=i)vis[j]=1;
    for(int i=4; i<=10000; i++)
        if(vis[i])for(int j=i; j<=10000; j+=i)d[j].push_back(i);
    int T;
    cin>>T;
    while(T--)
    {
        ans=0;
        cin>>n>>rt;
        memset(vis,0,sizeof vis);
        for(int i=1; i<=n; i++)v[i].clear();
        for(int i=1,x,y; i<n ; i++)
            cin>>x>>y,v[x].push_back(y),v[y].push_back(x);
        for(int i=1; i<=n; i++)cin>>val[i];
        dfs(rt,-1);
        cout<<ans<<'\n';
    }
}

 

Change

 

There is a rooted tree with n nodes, number from 1-n. Root’s number is 1.Each node has a value ai.

Initially all the node’s value is 0.

We have q operations. There are two kinds of operations.

1 v x k : a[v]+=x , a[v’]+=x-k (v’ is child of v) , a[v’’]+=x-2*k (v’’ is child of v’) and so on.

2 v : Output a[v] mod 1000000007(10^9 + 7).

Input

First line contains an integer T (1 ≤ T ≤ 3), represents there are T test cases.

In each test case:

The first line contains a number n.

The second line contains n-1 number, p2,p3,…,pn . pi is the father of i.

The third line contains a number q.

Next q lines, each line contains an operation. (“1 v x k” or “2 v”)

1 ≤ n ≤ 3*10^5

1 ≤ pi < i

1 ≤ q ≤ 3*10^5

1 ≤ v ≤ n; 0 ≤ x < 10^9 + 7; 0 ≤ k < 10^9 + 7

Output

For each operation 2, outputs the answer.

Sample Input

1
3
1 1
3
1 1 2 1
2 1
2 2

Sample Output

2
1

这个题目的题意还是很简单的,就是一个访问x,就把它+x,他的孩子要多减去k,孙子多减2k

可以考虑用两个树状数组维护,一个维护x+deep[v]*k,一个-k

#include<stdio.h>
#include<vector>
using namespace std;
const int N=3e5+5,MD=1e9+7;
int L[N],R[N],deep[N],n;
int a[N],b[N];
int tot;
vector<int>G[N];
void dfs(int u)//处理出dfs序与每个点的深度
{
    L[u]=++tot;
    int l=G[u].size();
    for(int i=0,v; i<l; i++)
    {
        v=G[u][i];
        deep[v]=deep[u]+1;
        dfs(v);
    }
    R[u]=tot;
}
//差分思想
void adda(int x,int y)//维护x+deep[v]*k
{
    for(int i=x; i<=n; i+=(i&-i)) a[i]=(a[i]+y)%MD;
}

void addb(int x,int y)//维护-k
{
    for(int i=x; i<=n; i+=(i&-i)) b[i]=(b[i]+y)%MD;
}

int sum(int x,int y)
{
    int ret=0,ans=0;
    for(int i=x; i; i-=(i&-i)) ret=(ret*1LL+a[i])%MD;
    for(int i=x; i; i-=(i&-i)) ans=(ans*1LL+b[i])%MD;
    ans=ans*1LL*(deep[y]+1)%MD;
    return (ret+ans)%MD;
}
int main()
{
    int T,q;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=2,x; i<=n; i++)scanf("%d",&x),G[x].push_back(i);
        tot=0;
        dfs(1);
        scanf("%d",&q);
        for(int i=0,op,v,x,k; i<q; i++)
        {
            scanf("%d%d",&op,&v);
            if(op==1)
            {
                scanf("%d%d",&x,&k);
                int ret=(x+(deep[v]+1)*1LL*k)%MD;
                adda(L[v],ret);
                adda(R[v]+1,-ret+MD);
                addb(L[v],(-k+MD)%MD);
                addb(R[v]+1,k%MD);
            }
            else
                printf("%d\n",sum(L[v],v));
        }
        for(int i=1; i<=n; i++)G[i].clear(),a[i]=b[i]=deep[i]=0;
    }
}

 

转载于:https://www.cnblogs.com/BobHuang/p/9650048.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值