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;
    }
  • 相关阅读:
    您知道SASS吗?
    打破技术壁垒, 用SpreadJS 抢占“表格文档协同编辑系统”的入市先机
    7种你应该知道的JavaScript常见的错误
    前端开发:这10个Chrome扩展你不得不知
    疫情下,买菜难,其实卖菜的也是这么想的
    疫情之下远程办公,开启企业办公的全新时代!
    “泛在电力物联网”究竟是什么?
    2020 春节集五福最详细收集攻略
    怎样使我们的用户不再抵触填写Form表单?
    新事业,新征程:换屏哥,您身边的手机维修专家
  • 原文地址:https://www.cnblogs.com/wangfang20/p/3259161.html
Copyright © 2011-2022 走看看