zoukankan      html  css  js  c++  java
  • hdu 4670 树的点分治

    思路:首先当然是要用树的点分治了。根节点为root,那么经过root的合法路径数求出来这题就解决了。因为我们可以用分治枚举根,最后将所有根的路径数加起来就是结果。当然这里的根不是整棵树的根,是子树根。

    我们为每个节点分配一个长度为30的数组记录给定因数在每个节点权值出现的次数。如果某几个权值相乘的值Value的三次根仍是整数的话,那么Value在给定因数的所有幂一定是3的倍数。通过这个转换,我们将所有的幂都对3取余,结果还是一样。

    在判断经过root的合法路径数时,我们进入其一个子树,将经过的路径因数的幂相加,判读其是否有对立状态存在,若存在,结果+1。所谓对立状态就是能够合成合法路径的状态。

    例如因数为 2,3,5.

    那么 x节点的状态为 0,1,2 表示2的0次幂,3的1次幂,5的2次幂。

    其对立状态就是 0,2,1。因为他这两条路径合成一条后,就变成了0,3,3.都是3的倍数。

    状态数的记录,我们可以用long long 型的map。

    要加栈,不然会RE。我就连续两次RE,加了就AC了。

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #include<vector>
    #include<map>
    #define Maxn 100010
    #define Maxm 200010
    #define LL __int64
    #define inf 0x7fffffff
    using namespace std;
    map<LL,LL> hash;
    int head[Maxn],vi[Maxn],e,ans,num,k,n,m,prime[31],lans;
    int mx[Maxn],mi,dis[Maxn],root,size[Maxn];
    LL Exp[31];
    struct Node{
        int cnt[31];
    }node[Maxn];
    struct Edge{
        int u,v,val,next;
    }edge[Maxm];
    vector <Node> q;
    void init()
    {
        memset(vi,0,sizeof(vi));
        memset(head,-1,sizeof(head));
        memset(mx,0,sizeof(mx));
        memset(dis,0,sizeof(dis));
        q.clear();
        hash.clear();
        Exp[0]=1;
        for(int i=1;i<=30;i++)
            Exp[i]=Exp[i-1]*3;
        e=ans=lans=0;
    }
    void add(int u,int v)
    {
        edge[e].u=u,edge[e].v=v,edge[e].next=head[u],head[u]=e++;
        edge[e].u=v,edge[e].v=u,edge[e].next=head[v],head[v]=e++;
    }
    void dfssize(int u,int fa)
    {
        int i,v;
        size[u]=1;
        mx[u]=0;
        for(i=head[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].v;
            if(v!=fa&&!vi[v])
            {
                dfssize(v,u);
                size[u]+=size[v];
                if(size[v]>mx[u]) mx[u]=size[v];
            }
        }
    }
    void dfsroot(int r,int u,int fa)
    {
        int v,i;
        if(size[r]-size[u]>mx[u]) mx[u]=size[r]-size[u];
        if(mx[u]<mi) mi=mx[u],root=u;
        for(i=head[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].v;
            if(v!=fa&&!vi[v])
            {
                dfsroot(r,v,u);
            }
        }
    }
    void dfsdis(int u,Node d,int fa)
    {
        int i,v,j;
        q.push_back(d);
        LL cc=0;
        for(j=1;j<=k;j++)//判断其是否存在对立状态
        {
            cc+=(3-(d.cnt[j]+node[root].cnt[j])%3)%3*Exp[j];
        }
        lans+=hash[cc];//答案加上对立状态数
        Node temp;
        for(i=head[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].v;
            if(v!=fa&&!vi[v])
            {
                for(j=1;j<=k;j++)
                {
                    temp.cnt[j]=(d.cnt[j]+node[v].cnt[j])%3;
                }
                dfsdis(v,temp,u);
            }
        }
    }
    int calc(int u)
    {
        int i,j,ret=0,sz,v;
        lans=0;
        hash.clear();
        hash[0]=1;
        for(i=head[u];i!=-1;i=edge[i].next)
        {
            q.clear();
            v=edge[i].v;
            if(!vi[v])
            {
                dfsdis(v,node[v],u);
                sz=q.size();
                //cout<<u<<" "<<v<<" "<<sz<<endl;
                for(int r=0;r<sz;r++)//回退时,记录这条子路径上的所有状态数。
                {
                    LL cc=0;
                    for(j=1;j<=k;j++)
                    {
                        cc+=q[r].cnt[j]*Exp[j];
                    }
                    hash[cc]++;
                }
            }
        }
        return lans;
    }
    void dfs(int u)
    {
        int i,v,j;
        mi=n;
        dfssize(u,0);
        dfsroot(u,u,0);
        ans+=calc(root);
        //cout<<root<<"************"<<endl;
        vi[root]=1;
        for(i=head[root];i!=-1;i=edge[i].next)
        {
            v=edge[i].v;
            if(!vi[v])
            {
                dfs(v);
            }
        }
    }
    int main()
    {
        int i,j,u,v;
        LL x;
        while(scanf("%d",&n)!=EOF)
        {
            init();
            scanf("%d",&k);
            for(i=1;i<=k;i++)
                scanf("%d",&prime[i]);
            for(i=1;i<=n;i++)
            {
                scanf("%I64d",&x);
                memset(node[i].cnt,0,sizeof(node[i].cnt));
                for(j=1;j<=k;j++)
                {
                    while(x%prime[j]==0&&x!=0)
                    {
                        node[i].cnt[j]++;
                        node[i].cnt[j]%=3;
                        x/=prime[j];
                    }
                    if(x==0)
                        break;
                }
                int cc=0;
                for(j=1;j<=k;j++)
                    cc+=node[i].cnt[j];
                if(cc==0)
                    ans++;
            }
            //printf("&&&&&&&&&&&&
    ");
            for(i=1;i<n;i++)
            {
                scanf("%d%d",&u,&v);
                add(u,v);
            }
            dfs(1);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    软件测试人员的年终绩效考核怎么应对
    收藏
    顶踩组件 前后两版
    订阅组件
    hdu 1963 Investment 完全背包
    hdu 4939 Stupid Tower Defense 动态规划
    hdu 4405 Aeroplane chess 动态规划
    cf 414B Mashmokh and ACM 动态规划
    BUPT 202 Chocolate Machine 动态规划
    hdu 3853 LOOPS 动态规划
  • 原文地址:https://www.cnblogs.com/wangfang20/p/3259161.html
Copyright © 2011-2022 走看看