树基于点的分治

除转载的四道例题外,还有

hdu 4670

******************************************************分割线,接下来是代码**************************************************

//BZOJ 2599
//点按[1,n]存,0有特殊用
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
#define N 200005
#define C 1000005
struct edge{
    int to,next,w;
}e[N<<1];
int n,m;
int root,size,ans,o;
int s[N],f[N],d[N],ee[N],head[N],c[C],v[C];
vector<int> dep;
bool done[N];

void add(int x,int y,int z)
{
    e[o].to=y;
    e[o].w=z;
    e[o].next=head[x];
    head[x]=o++;
}
void getroot(int now, int fa) {
    int u;
    s[now] = 1; f[now] = 0;
    for (int i=head[now]; ~i; i=e[i].next)
        if ((u =e[i].to)!= fa)
        {   if (done[u]) continue;
            getroot(u, now);
            s[now] += s[u];
            f[now] = max(f[now], s[u]);
        }
    f[now] = max(f[now], size-s[now]);
    if (f[now] < f[root]) root = now;
}
void dfs1(int now, int fa) {

    int u;
    if (d[now] > m) return;
    if (v[m-d[now]] == root)
        ans=min(ans,c[m-d[now]] + ee[now]);
    for (int i = head[now]; ~i; i = e[i].next)
        if ((u =e[i].to)!= fa)
        {   if (done[u]) continue;
            d[u] = d[now] + e[i].w;
            ee[u] = ee[now] + 1;
            dfs1(u, now);
        }
}
void dfs2(int now, int fa) {

    int u;
    if (d[now] > m) return;
    if (v[d[now]] != root) {
        c[d[now]] = ee[now];
        v[d[now]] = root;
    }
    else
        c[d[now]]=min(c[d[now]],ee[now]);
    for (int i = head[now]; ~i; i = e[i].next)
        if ((u =e[i].to)!= fa)
        {   if (done[u]) continue;
            dfs2(u, now);
        }
}


void work(int now) {
    int u;

    v[0]=root;
    done[now] = true;
    for (int i=head[now]; ~i; i=e[i].next)
        if (!done[u =e[i].to])
        {   d[u] = e[i].w;
            ee[u] = 1;
            dfs1(u, now);
            dfs2(u, now);
        }
    for (int i=head[now]; ~i; i=e[i].next)
        if (!done[u =e[i].to])
        {
            f[0] = size = s[u]; getroot(u, root=0); work(root);
        }
}
void doit()
{
    ans = n;   memset(done, 0, sizeof(done));

    memset(head,255,sizeof(head)); o=0;
    for (int i=1,x,y,w; i<n; i++)
        {
            scanf("%d%d%d", &x, &y, &w);x++; y++;
            add(x,y,w);
            add(y,x,w);
        }
    f[0] = size = n;  getroot(1, root=0);  work(root);
    printf("%d\n", ans < n ? ans : -1);
}
int main()
{   while (scanf("%d%d",&n,&m)!=EOF) doit();
    return 0;
}
/*
4 3
0 1 1
1 2 2
1 3 4
*/


//Hdu 4670
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
using namespace std;
#define N 50005
#define C 100005
#define T 32
typedef long long LL;
struct edge{
    int to,next;
}e[N<<1];

int n,root,size,o,pr,equ,oo;
LL ans,total[T];
map<LL,int> mm;
int s[N],f[N],d[N][T],head[N],c[C];
LL res[C];
LL pri[T];
vector<int> dep;
bool done[N];
int num[N][T];

void add(int x,int y)
{
    e[o].to=y;
    e[o].next=head[x];
    head[x]=o++;
}
void getroot(int now, int fa) {
    int u;
    s[now] = 1; f[now] = 0;
    for (int i=head[now]; ~i; i=e[i].next)
        if ((u =e[i].to)!= fa)
        {   if (done[u]) continue;
            getroot(u, now);
            s[now] += s[u];
            f[now] = max(f[now], s[u]);
        }
    f[now] = max(f[now], size-s[now]);
    if (f[now] < f[root]) root = now;
}
void dfs(int now,int fa)
{   int tmp,u;
    LL s1=0,s2=0;
    for (int i=0;i<pr;i++)
        {
            d[now][i]=d[fa][i]+num[now][i];
            if (d[now][i]>2) d[now][i]-=3;
            tmp=(total[i]+3-d[now][i])%3;
            s1=s1*3+d[now][i];
            s2=s2*3+tmp;
        }
    if (s1==s2) equ++;
    if (mm.find(s1)==mm.end()) {mm[s1]=oo;res[oo]=s2;c[oo++]=1;}else {c[mm[s1]]++;}
    for (int i=head[now];~i;i=e[i].next)
         if ((u=e[i].to)!=fa)
         {  if (done[u]) continue;
            dfs(u, now);
         }

}
LL calc(int now,int fa)
{
    mm.clear();//memset(c,0,sizeof(c)); 加上这句会T
    equ=0; oo=0;
    if (fa)
         for (int i=0;i<pr;i++) total[i]=num[fa][i];
    else for (int i=0;i<pr;i++) total[i]=num[now][i];
    dfs(now,fa);
    LL re=0;
    for (int i=0;i<oo;i++)
        {   if (mm.find(res[i])!=mm.end())
            re+=c[i]*c[mm[res[i]]];
        }
    return (re-equ)/2+equ;
}
void work(int now) {
    int u;
    done[now] = true;
    ans+=calc(root,0);
    for (int i=head[now]; ~i; i=e[i].next)
        if (!done[u =e[i].to])
        {   ans-=calc(u,now);
            f[0] = size = s[u]; getroot(u, root=0);  work(root);
        }
}
void doit()
{   ans = 0;   memset(done, 0, sizeof(done));
    scanf("%d",&pr);
    for (int i=0;i<pr;i++)
        scanf("%I64d",&pri[i]);
    memset(num,0,sizeof(num));
    for (int i=1;i<=n;i++)
        {   LL x;
            scanf("%I64d",&x);
            for (int j=0;j<pr;j++)
                {   while (x%pri[j]==0)
                         {
                             x/=pri[j];
                             num[i][j]++;
                         }
                    num[i][j]%=3;
                }
        }
    memset(head,255,sizeof(head)); o=0;
    for (int i=1,x,y; i<n; i++)
        {
            scanf("%d%d", &x, &y);
            add(x,y);
            add(y,x);
        }
    f[0] = size = n;  getroot(1, root=0);  work(root);
    printf("%I64d\n",ans);
}
int main()
{   while (scanf("%d",&n)!=EOF) doit();
    return 0;
}
/*
4
2 2 5
100 10 100 10
1 2
2 3
3 4

7
1 2
2 2 2 2  2 2 2
1 2
1 3
2 4
2 5
3 6
3 7

5
3 2 3 5
2500 200 9 270000 27
4 2
3 5
2 5
4 1

6
3 2 3 5
6 1 30 150 150 12
1 2
2 4
1 3
3 5
3 6

ans:
4
7
1
4
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值