hdu4670 Cube number on a tree 点分治

Posted __560

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu4670 Cube number on a tree 点分治相关的知识,希望对你有一定的参考价值。

 这次写不容斥的版本,WA了好几次,又改成容斥的,还是没过,一怒之下把所有的int改成longlong就过了。。。

技术分享
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<map>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

ll N,K;
ll p[maxn];
ll val[maxn];
ll u,v;
ll e[maxn],tot;
ll first[maxn],Next[maxn];
bool vis[maxn];
ll rt,balance;
map<ll,ll> id;
ll d[maxn],dn;
ll s[maxn];

void Init()
{
    tot=0;
    memset(first,-1,sizeof(first));
}

void addedge(ll u,ll v)
{
    e[++tot]=v;
    Next[tot]=first[u];
    first[u]=tot;
}

ll qpow(ll n,ll k)
{
    ll res=1;
    while(k){
        if(k&1) res*=n;
        n*=n;
        k>>=1;
    }
    return res;
}

ll toCube(ll x)
{
    ll res=0;
    REP(i,0,K-1){
        ll cur=0;
        while(x%p[i]==0){
            cur++;
            x/=p[i];
        }
        res+=qpow(3,i)*(cur%3);
    }
    return res;
}

ll add3(ll a,ll b)
{
    ll c=0,x=0,y=0;
    ll t=1;
    REP(i,0,K-1){
        x=a%3;a/=3;
        y=b%3;b/=3;
        c+=((x+y)%3)*t;
        t*=3;
    }
    return c;
}

ll cut3(ll a,ll b)
{
    ll c=0,x=0,y=0;
    ll t=1;
    REP(i,0,K-1){
        x=a%3;a/=3;
        y=b%3;b/=3;
        c+=((x-y+3)%3)*t;
        t*=3;
    }
    return c;
}

void dfs_d(ll u,ll f,ll dep)
{
    d[++dn]=u;
    s[u]=dep;
    for(int i=first[u];~i;i=Next[i]){
        int v=e[i];
        if(v==f||vis[v]) continue;
        dfs_d(v,u,add3(dep,val[v]));
    }
}

ll get_rt(ll u,ll f,int sz)
{
    ll cnt=1,balance1=0;
    for(int i=first[u];~i;i=Next[i]){
        int v=e[i];
        if(v==f||vis[v]) continue;
        ll tmp=get_rt(v,u,sz);
        cnt+=tmp;
        balance1=max(balance1,tmp);
    }
    balance1=max(balance1,sz-cnt);
    if(balance1<balance){
        balance=balance1;
        rt=u;
    }
    return cnt;
}

ll solve(int u)
{
    rt=u;balance=INF;
    ll sz=get_rt(u,0,N);
    rt=u;balance=INF;
    get_rt(u,0,sz);
    u=rt;
    vis[u]=1;
    ll res=0;
    id.clear();
    s[u]=val[u];
    id[s[u]]++;
    if(val[u]==0) res++;
    for(ll i=first[u];~i;i=Next[i]){
        int v=e[i];
        if(vis[v]) continue;
        dn=0;
        dfs_d(v,u,add3(val[u],val[v]));
        REP(j,1,dn){
            ll idx=d[j],x=s[idx];
            ll y=cut3(val[u],x);
            res+=id[y];
        }
        REP(j,1,dn){
            ll idx=d[j],x=s[idx];
            id[x]++;
        }
    }
    for(int i=first[u];~i;i=Next[i]){
        int v=e[i];
        if(vis[v]) continue;
        res+=solve(v);
    }
    return res;
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&N,&K)){
        REP(i,0,K-1) scanf("%I64d",&p[i]);
        REP(i,1,N){
            ll x;scanf("%I64d",&x);
            val[i]=toCube(x);
            //cout<<"i="<<i<<" val[i]="<<val[i]<<" x="<<x<<endl;
        }
        Init();
        REP(i,1,N-1){
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        MS0(vis);
        printf("%I64d\n",solve(1));
    }
    return 0;
}
/**
5
3 2 3 5
2500 200 9 270000 27
4 2
3 5
2 5
4 1

2
2 3 5
9 3
1 2

6
3 2 3 5
10 10 10 10 10 10
1 2
2 3
3 4
4 5
5 6

6
3 2 3 5
216 10 10 10 25 5
1 2
2 3
3 4
4 5
5 6

12
3 2 3 5
1 3 5 3 3 9 1 5 5 2 4 2
1 4
4 2
4 5
4 6
4 7
2 3
5 8
5 9
6 10
6 11
7 12

5
3  2 3 5
1 1 1 1 1
1 2
1 3
1 4
1 5



*/
View Code

 

以上是关于hdu4670 Cube number on a tree 点分治的主要内容,如果未能解决你的问题,请参考以下文章

HDU 4670 Cube number on a tree ( 树的点分治 )

HDU 1221: Cube

SDUT 3257 Cube Number 简单数学

hdu-3584 Cube---三维树状数组+区域更新单点查询

hdu6330 多校3 L 画一个cube

HDU - 3584 Cube (三维树状数组 + 区间改动 + 单点求值)