树基于点的分治

来源:互联网 发布:linux php 写入权限 编辑:程序博客网 时间:2024/05/16 14:05

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

hdu 4670

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

//BZOJ 2599//点按[1,n]存,0有特殊用#include <cstdio>#include <algorithm>#include <vector>#include <cstring>using namespace std;#define N 200005#define C 1000005struct 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 30 1 11 2 21 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 32typedef 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;}/*42 2 5100 10 100 101 22 33 471 22 2 2 2  2 2 21 21 32 42 53 63 753 2 3 52500 200 9 270000 274 23 52 54 163 2 3 56 1 30 150 150 121 22 41 33 53 6ans:4714*/


0 0