zoukankan      html  css  js  c++  java
  • 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个节点有属性值vali, 定义F(i): 在以i为根的子树中,属性值是vali的合约数的节点个数。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<<'
    ';
        }
    }

    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
    ",sum(L[v],v));
            }
            for(int i=1; i<=n; i++)G[i].clear(),a[i]=b[i]=deep[i]=0;
        }
    }
  • 相关阅读:
    数据中心网络架构的问题与演进 — NFV
    数据中心网络架构的问题与演进 — 云网融合与 SD-WAN
    数据中心网络架构的问题与演进 — 混合云与 VPC 专有网络
    数据中心网络架构的问题与演进 — SDN
    数据中心网络架构的问题与演进 — Overlay 网络
    ASP.NET MVC- Controllers and Routing- Controller Overview
    ASP.NET MVC- VIEW Creating Page Layouts with View Master Pages Part 4
    ASP.NET MVC- VIEW Using the TagBuilder Class to Build HTML Helpers Part 3
    ASP.NET MVC- VIEW Creating Custom HTML Helpers Part 2
    ASP.NET MVC- VIEW Overview Part 1
  • 原文地址:https://www.cnblogs.com/BobHuang/p/9650048.html
Copyright © 2011-2022 走看看