zoukankan      html  css  js  c++  java
  • E. Alternating Tree 树点分治|树形DP

    题意:给你一颗树,然后这颗树有n*n条路径,a->b和b->a算是一条,然后路径的权值是 vi*(-1)^(i+1)  注意是点有权值。

    从上头往下考虑是点分治,从下向上考虑就是树形DP,分成三类路径:1.指定点单点 2.跨过指定点3.没跨过指定点但不是单点

    细节要好好打磨一下,然后还是用long long比较稳 ,1LL*还是有点危险.

    点分治:

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=2e5+88;
    const int P=1e9+7;
    vector<int>G[N];
    bool vis[N];
    int SQ,SO,Q,O,q[N],o[N],rt,m,nq[N],no[N],sz[N],v[N],mx[N],ans;
    void dfs(int u,int fa,int S){
        sz[u]=mx[u]=1; 
        q[u]=o[u]=no[u]=nq[u]=0;
        for(int i=0;i<(int)G[u].size();++i) {
            int v=G[u][i];
            if(vis[v]||v==fa) continue;
            dfs(v,u,S);
            sz[u]+=sz[v];
            mx[u]=max(mx[u],sz[v]);
        }
        mx[u]=max(mx[u],S-sz[u]);
        if(m>mx[u]) rt=u,m=mx[u];
    }
    void solve(int u,int nv,int f,int fa,int last){
        int t=(nv+f*v[u])%P;
        if(f==-1) o[fa]=(o[fa]+t)%P,O=(O+t)%P,++no[fa],++SO;
        else q[fa]=(q[fa]+t)%P,Q=(Q+t)%P,++nq[fa],++SQ;
        for(int i=0;i<(int)G[u].size();++i) {
            int v=G[u][i];
            if(v==last||vis[v]) continue;
            solve(v,t,-f,fa,u);
        }
    }
    int work(int u,int S){
        m=1e9+7;
        dfs(u,0,S);
        vis[rt]=1;
        Q=O=SQ=SO=0;
        for(int i=0;i<(int)G[rt].size();++i) if(!vis[G[rt][i]]) solve(G[rt][i],v[rt],-1,G[rt][i],rt);
        for(int i=0;i<(int)G[rt].size();++i) if(!vis[G[rt][i]]){
            int t=G[rt][i];
            ans=((ans-1LL*no[t]*(O-o[t])%P)%P-1LL*o[t]*(SO-no[t])%P)%P;
            ans=(ans+1LL*no[t]*(SO-no[t])%P*v[rt]%P)%P;
            ans=((ans+1LL*nq[t]*(Q-q[t])%P)%P+1LL*q[t]*(SQ-nq[t])%P)%P;
            ans=(ans-1LL*nq[t]*(SQ-nq[t])%P*v[rt]%P)%P;
            ans=(ans+(q[t]<<1)%P)%P;
        }
        ans=((ans+v[rt])%P+P)%P; 
        int nt=rt;
        for(int i=0;i<(int)G[nt].size();++i) if(!vis[G[nt][i]]) 
        work(G[nt][i],sz[G[nt][i]]>sz[nt]?S-sz[nt]:sz[G[nt][i]]);
    }
    int main(){
        int n,x,y;
        scanf("%d",&n);
        for(int i=1;i<=n;++i) scanf("%d",v+i);
        for(int i=1;i<n;++i) {
            scanf("%d%d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
        } 
        work(1,n);
        printf("%d
    ",(ans+P)%P);
    }

    树形DP的思路是参考的这里

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=2e5+88;
    const int P=1e9+7;
    vector<int>G[N];
    long long dp[N][2],num[N][2],ans,v[N];
    void dfs(int u,int fa){
        for(int i=0;i<(int)G[u].size();++i) {
            int vt=G[u][i];
            if(vt==fa) continue;
            dfs(vt,u);
            dp[u][0]=(((dp[u][0]+dp[vt][1])%P-1LL*v[u]*num[vt][1]%P)%P+P)%P;
            dp[u][1]=(((dp[u][1]+dp[vt][0])%P+1LL*v[u]*num[vt][0]%P)%P+P)%P;
            num[u][0]=(num[u][0]+num[vt][1])%P;
            num[u][1]=(num[u][1]+num[vt][0])%P;
        }
        for(int i=0;i<(int)G[u].size();++i) {
            int vt=G[u][i];
            if(vt==fa) continue;
            ans=(ans+2LL*(num[u][1]-num[vt][0])%P*dp[vt][0]%P+1LL*(num[u][1]-num[vt][0])*v[u]%P*num[vt][0]%P)%P;
            ans=(ans+2LL*(num[u][0]-num[vt][1])%P*dp[vt][1]%P-1LL*(num[u][0]-num[vt][1])*v[u]%P*num[vt][1]%P)%P;
        }
        ans=(ans+(dp[u][1]<<1)%P+v[u])%P;
        ++num[u][1];
        num[u][1]%=P;
        dp[u][1]=(dp[u][1]+v[u])%P;
    }
    int main(){
        int n,x,y;
        scanf("%d",&n);
        for(int i=1;i<=n;++i) scanf("%lld",v+i);
        for(int i=1;i<n;++i) {
            scanf("%d%d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
        } 
        dfs(1,0);
        printf("%lld
    ",(ans+P)%P);
    }
  • 相关阅读:
    python模块导入
    linux总结shell
    linux和shell关系
    gdb调试工具
    C语言.c和.h
    CSS cursor 属性
    html dom SetInterVal()
    css hover伪类选择器与JQuery hover()方法
    CSS 清除浮动 clear 属性
    block,inline和inline-block概念和区别
  • 原文地址:https://www.cnblogs.com/mfys/p/8810857.html
Copyright © 2011-2022 走看看