Codeforces 161D Distance in Tree(点分治/树形dp)

题意:给出一个树,求有多少对节点间的距离等于k,n<5e4, k<500

题解:解法一:点分治,k很小,在拿一个桶统计一下,注意统计的时候要判断时候和本身相同,相同要减一

#include <bits/stdc++.h>
#define IO_read ios::sync_with_stdio(false);cin.tie(0)
#define fre freopen("in.txt", "r", stdin)
#define _for(i,a,b) for(int i=a; i< b; i++)
#define _rep(i,a,b) for(int i=a; i<=b; i++)
#define inf 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
using namespace std;
typedef long long ll;
template <class T>
void read(T &x)
{
    char c; bool op=0;
    while(c=getchar(), c<'0'||c>'9') if(c=='-') op=1;
    x=c-'0';
    while(c=getchar(), c>='0'&&c<='9') x=x*10+c-'0';
    if(op) x=-x;
}
template <class T>
void write(T x)
{
    if(x<0) putchar('-'), x=-x;
    if(x>=10) write(x/10);
    putchar('0'+x%10);
}

const int maxn=5e4+5;
int head[maxn], tot;
struct Edge{
    int to, next, val;
}edge[maxn*2];

void addedge(int u, int v, int w)
{
    edge[++tot]={v, head[u], w};
    head[u]=tot;
}

int n, k;
ll ans;
int sz[maxn], vis[maxn], bucket[505], max_son, rt, Size;
ll dis[maxn], q[maxn];
int l, r;

void get_rt(int u, int fa)
{
    sz[u]=1;
    int num=0;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to;
        if(vis[v] || v==fa) continue;
        get_rt(v, u);
        sz[u]+=sz[v];
        num=max(num, sz[v]);
    }
    num=max(num, Size-sz[u]);
    if(num<max_son) max_son=num, rt=u;
}

void get_dis(int u, int fa)
{
    q[++r]=dis[u];
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to, w=edge[i].val;
        if(vis[v] || v==fa) continue;
        dis[v]=dis[u]+w;
        get_dis(v, u);
    }
}

ll solve(int u, int val)
{
    l=1, r=0, dis[u]=val;
    get_dis(u, 0);
    ll res=0;
    sort(q+1, q+1+r);
    memset(bucket, 0, sizeof(bucket));
    for(int i=1; i<=r&&q[i]<=k; i++)
        bucket[q[i]]++;
    for(int i=1; i<=r&&q[i]<=k; i++)
    {
        if(k-q[i]==q[i]) res+=bucket[k-q[i]]-1;
        else res+=bucket[k-q[i]];
    }
    /*
    for(int i=1; i<=r; i++) printf("%d ", q[i]);
    printf("\n");
    printf("res=%d, k=%d\n", res);
    */
    res=res/2;
    return res;
}

void divide(int u)
{
    ans+=solve(u, 0);
    vis[u]=true;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to, w=edge[i].val;
        if(vis[v]) continue;
        ans-=solve(v, w);  //容斥
        Size=sz[v], max_son=inf;
        get_rt(v, 0);
        divide(rt);
    }
}

int main()
{
    IO_read;
    //fre;
    cin>>n>>k;
    memset(head, -1, sizeof(head));
    for(int i=1,u,v; i<n; i++)
    {
        cin>>u>>v;
        addedge(u, v, 1), addedge(v, u, 1);
    }
    Size=n, max_son=inf;
    get_rt(1, 0);
    divide(rt);
    cout<<ans<<"\n";
}
View Code

  解法二:树形dp,待解决

posted @ 2019-10-27 22:31  N_Yokel  阅读(169)  评论(0编辑  收藏  举报