• 8/24 差分lca+数学(抽屉原理)


    P1351 [NOIP2014 提高组] 联合权值

    思路:
    1.需要找到中间结点.若该点周围有两个顶点,则贡献为(a+b)^2- a^2 -b^2;若该点周围有三个顶点,则贡献为2ab+2ac+2bc=(a+b+c)^2-a^2-b^2-c^2
    2.对于贡献的最大值,不需要进行取模操作。
    3.对于每一个点进行判断,所有和它相连的点彼此间距离都为2,在其中判断出最大值,累加和即可。

    #include
    #define int long long
    #define endl '\n'
    #define For(i,a,b) for(i=(a);i<=(b);++i)
    #define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
    using namespace std;
    const int N=7e5+7;
    const int inf=0x3f3f3f3f;
    const int mod=1e4+7;
    int n,a[N],ans,mx;
    int dep[N];     //存u点的深度
    int fa[N][20];  //存从u点向上跳2^i层的祖先节点
    vector<int>e[N];
    void dfs(int u,int pare)
    {
        dep[u]=dep[pare]+1;
        fa[u][0]=pare;
        for(int i=1;i<=19;i++)
            fa[u][i]=fa[fa[u][i-1]][i-1];
        for(int v:e[u])
            if(v!=pare) dfs(v,u);
    }
    
    //利用st表求lca
    int lca(int u,int v)
    {
        if(dep[u]<dep[v]) swap(u,v);
        for(int i=19;i>=0;i--)
            //先跳到同一层
            if(dep[fa[u][i]]>=dep[v])
                u=fa[u][i];
        if(u==v)    return v;
        //跳到lca的下一层
        for(int i=19;i>=0;i--)
            if(fa[u][i]!=fa[v][i])
            u=fa[u][i],v=fa[v][i];
        return fa[u][0];
    }
    
    void solve()
    {
        cin>>n;
        for(int i=1;i<n;i++)
        {
            int u,v;cin>>u>>v;
            e[u].push_back(v);e[v].push_back(u);
        }
        for(int i=1;i<=n;i++)
            cin>>a[i];
        int mx=0;
        for(int i=1;i<=n;i++)
        {
            int mx1=0,mx2=0;
            int t1=0,t2=0;
            for(int j:e[i])
            {
                if(a[j]>mx1) mx2=mx1,mx1=a[j];
                else if(a[j]>mx2)
                    mx2=a[j];
                t1=(t1+a[j])%mod;
                t2=(t2+a[j]*a[j])%mod;
            }
            t1=t1*t1%mod;
            ans=(ans+t1-t2+mod)%mod;
            if(mx<mx1*mx2)
                mx=mx1*mx2;
        }
        cout<<mx<<" "<<ans<<endl;
    }
    signed main()
    {
        //ios;
        //int T;cin>>T;
        //while(T--)
            solve();
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    P3258 [JLOI2014]松鼠的新家

    差分LCA,将一条路径上经过的点都加上1
    处理方法:将两个起点都加上1,其lca的值g减去1,再将g的父亲f[g][0]的值减去1

    #include
    #define int long long
    #define endl '\n'
    #define For(i,a,b) for(i=(a);i<=(b);++i)
    #define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
    using namespace std;
    const int N=7e5+7;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    int n,a[N],ans,mx,num[N];
    int dep[N];     //存u点的深度
    int fa[N][20];  //存从u点向上跳2^i层的祖先节点
    vector<int>e[N];
    void dfs(int u,int pare)
    {
        dep[u]=dep[pare]+1;
        fa[u][0]=pare;
        for(int i=1;i<=19;i++)
            fa[u][i]=fa[fa[u][i-1]][i-1];
        for(int v:e[u])
            if(v!=pare) dfs(v,u);
    }
    
    //利用st表求lca
    int lca(int u,int v)
    {
        if(dep[u]<dep[v]) swap(u,v);
        for(int i=19;i>=0;i--)
            //先跳到同一层
            if(dep[fa[u][i]]>=dep[v])
                u=fa[u][i];
        if(u==v)    return v;
        //跳到lca的下一层
        for(int i=19;i>=0;i--)
            if(fa[u][i]!=fa[v][i])
            u=fa[u][i],v=fa[v][i];
        return fa[u][0];
    }
    void sum(int u,int pare)
    {
        for(int v:e[u])
        {
            if(v==pare) continue;
            sum(v,u);
            num[u]+=num[v];
        }
    }
    void solve()
    {
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        for(int i=1;i<n;i++)
        {
            int u,v;cin>>u>>v;
            e[u].push_back(v);e[v].push_back(u);
        }
        dfs(1,0);
        for(int i=1;i<n;i++)
        {
            int u=a[i],v=a[i+1];
            int g=lca(u,v);
            num[fa[g][0]]-=1;
            num[g]-=1;
            num[u]+=1;
            num[v]+=1;
        }
        sum(1,0);
        for(int i=2;i<=n;i++)
            num[a[i]]--;
        for(int i=1;i<=n;i++)
            cout<<num[i]<<endl;
    }
    signed main()
    {
        //ios;
        //int T;cin>>T;
        //while(T--)
            solve();
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    P6869 [COCI2019-2020#5] Putovanje

    思路:
    1.本题也是应用差分LCA,但不同的是,本题是对于边的差分,累加经过的边数,可直接将两点的lca直接减去2.
    2.可通过“反悔边”来确定所连的边,从而使用结构内其他成员c1,c2.

    #include
    #define int long long
    #define endl '\n'
    #define For(i,a,b) for(i=(a);i<=(b);++i)
    #define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
    using namespace std;
    const int N=7e5+7;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    int n,a[N],ans,head[N],cnt,num[N],c1[N],c2[N];
    struct node
    {
        int to,nxt,c1,c2;
    }e[N];
    void add(int from,int to,int c1,int c2)
    {
        e[++cnt].to=to;
        e[cnt].c1=c1;
        e[cnt].c2=c2;
        e[cnt].nxt=head[from];
        head[from]=cnt;
    }
    int dep[N];     //存u点的深度
    int fa[N][20];  //存从u点向上跳2^i层的祖先节点
    //vectore[N];
    void dfs(int u,int pare)
    {
        dep[u]=dep[pare]+1;
        fa[u][0]=pare;
        for(int i=1;i<=19;i++)
            fa[u][i]=fa[fa[u][i-1]][i-1];
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(v!=pare) dfs(v,u);
        }
    }
    
    //利用st表求lca
    int lca(int u,int v)
    {
        if(dep[u]<dep[v]) swap(u,v);
        for(int i=19;i>=0;i--)
            //先跳到同一层
            if(dep[fa[u][i]]>=dep[v])
                u=fa[u][i];
        if(u==v)    return v;
        //跳到lca的下一层
        for(int i=19;i>=0;i--)
            if(fa[u][i]!=fa[v][i])
            u=fa[u][i],v=fa[v][i];
        return fa[u][0];
    }
    void sum(int u,int pare)
    {
        int g;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(v==pare)
            {
                g=i;continue;
            }
            sum(v,u);
            num[u]+=num[v];
        }
        if(e[g].c1*num[u]<e[g].c2)
            ans+=e[g].c1*num[u];
        else
            ans+=e[g].c2;
    }
    void solve()
    {
        cin>>n;
        for(int i=1;i<n;i++)
        {
            int u,v,c1,c2;cin>>u>>v>>c1>>c2;
            add(u,v,c1,c2);
            add(v,u,c1,c2);
        }
        dfs(1,0);
        for(int i=1;i<n;i++)
        {
            int g=lca(i,i+1);
            num[g]-=2;
            num[i]+=1;
            num[i+1]+=1;
        }
        sum(1,0);
        cout<<ans<<endl;
    }
    signed main()
    {
        //ios;
        //int T;cin>>T;
        //while(T--)
            solve();
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100

    P5002 专心OI - 找祖先

    计算公式:(sz[i]-sz[j])*sz[j](i是j的父亲)+sz[i] (自身也可是自身的祖先)
    这种计算方式相较于其他方便了非常多。

    #include
    #define int long long
    #define endl '\n'
    #define For(i,a,b) for(i=(a);i<=(b);++i)
    #define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
    using namespace std;
    const int N=7e5+7;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    int n,r,m,a[N],mx,ans[N],sz[N];
    int dep[N];     //存u点的深度
    int fa[N][20];  //存从u点向上跳2^i层的祖先节点
    vector<int>e[N];
    void dfs(int u,int pare)
    {
        sz[u]=1;
        dep[u]=dep[pare]+1;
        fa[u][0]=pare;
        for(int i=1;i<=19;i++)
            fa[u][i]=fa[fa[u][i-1]][i-1];
        for(int v:e[u])
            if(v!=pare)
            {
                dfs(v,u);
                sz[u]+=sz[v];
            }
    }
    
    void solve()
    {
        cin>>n>>r>>m;
        for(int i=1;i<n;i++)
        {
            int u,v;cin>>u>>v;
            e[u].push_back(v);
            e[v].push_back(u);
        }
        dfs(r,0);
        for(int i=1;i<=n;i++)
        {
            for(int j:e[i])
            {
                if(j==fa[i][0]) continue;
                ans[i]=(ans[i]+(sz[i]-sz[j])*sz[j]%mod)%mod;
            }
            ans[i]=(ans[i]+sz[i])%mod;
        }
        while(m--)
        {
            int x;cin>>x;
            cout<<ans[x]<<endl;
        }
    
    }
    signed main()
    {
        //ios;
        //int T;cin>>T;
        //while(T--)
            solve();
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    C. Kuroni and Impossible Calculation

    思路:当n大于m时,肯定会出现两个数对m取模后值相同,若这两个数相减再对m取模后答案为0,在参与运算后ans=0;若n

    #include
    #define int long long
    #define endl '\n'
    #define For(i,a,b) for(i=(a);i<=(b);++i)
    #define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
    using namespace std;
    const int N=7e5+7;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    int n,m,a[N];
    
    void solve()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        if(n>m)
        {
            cout<<0<<endl;return;
        }
        int ans=1;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                ans=(ans*abs(a[i]-a[j]))%m;
        cout<<ans<<endl;
    }
    signed main()
    {
        //ios;
        //int T;cin>>T;
        //while(T--)
            solve();
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
  • 相关阅读:
    Python入门自学进阶-Web框架——26、DjangoAdmin项目应用-数据记录操作
    【数组】-找出数组中第一个重复的数字
    neo4jlinux服务器上的安装和配置
    Linux 下的Docker安装与IDEA配置远程Docker
    SpringBoot--redis自定义序列化配置不生效
    2毛钱不到的2A同步降压DCDC电压6V频率1.5MHz电感2.2uH封装SOT23-5芯片MT3520B
    SwiftUI 通过 ARKit 使用微笑控制 SwiftUI 视图(教程含源码)
    fplan-布局
    JWT安全及案例实战
    Upload-labs靶场
  • 原文地址:https://blog.csdn.net/weixin_51934288/article/details/126502357