bzoj1468: Tree 点分治

来源:互联网 发布:淘宝液晶显示器 编辑:程序博客网 时间:2024/05/22 10:40

今天考试,依旧打暴力咯。一看第一题绝壁是个虚树之类的东东。就是给你一棵树每次选几个点,给定几个点的控制范围,统计有多少点被控制。正解是离线+点分治+虚树。搞得我整个人都BB了。不过这场真是暴力出奇迹,竟然混到rank9 我也是醉了,网络赛就是水。。。。。

说正题:学习了一下点分治,我们从最基本的问题入手。LCT男人八题。不知不觉搞完一半了。。。。。

点分治的思想和分治差不多就是把一个东西分块,分成若干子问题,再合并。

这里为了保证分治的最优性我们要找树的重心,这样就能保证是2nlogn的复杂度

对于每个点我们先统计所有经过它的点对,再减去每个在同一个子树上的点对。

注意为了防止统计子树的时候重复统计其包含父节点的情况 我们要把每个统计完的点标记一下。

然后同一个子树里的点应该加上 这段边长*2 由于我的代码里面每个点的距离都+=次边边长,所以calc里面只用传原边长久可以了并不用*2.

#include <iostream>#include <algorithm>#include <cmath>#include <cstdio>#include <cstring>#include <vector>using namespace std;#define pb push_back#define maxn 50000struct node{    int v,l;};vector<node>g[maxn];vector<int>dep;int n,k,siz[maxn],nsiz,f[maxn],root,d[maxn],K,ans;bool vis[maxn];void getroot(int now,int fa){    int v;    siz[now]=1;f[now]=0;    for(int i=0;i<g[now].size();i++)    {        if((v=g[now][i].v)!=fa && !vis[v])        {            getroot(v, now);            siz[now]+=siz[v];            f[now]=max(f[now],siz[v]);        }    }    f[now]=max(f[now],nsiz-siz[now]);    if (f[now]<f[root])root = now;}void getdep(int now,int fa){    dep.pb(d[now]);    int v;siz[now]=1;    for(int i=0;i<g[now].size();i++)    {        v=g[now][i].v;        if(v==fa||vis[v]) continue;        d[v]=d[now]+g[now][i].l;        getdep(v,now);        siz[now]+=siz[v];    }}int calc(int now,int have){    dep.clear();d[now]=have;    getdep(now,0);    sort(dep.begin(),dep.end());    int ret=0;    for(int l=0,r=dep.size()-1;l<r;)    {        if(dep[l]+dep[r]<=K)        {            ret+=r-l;            l++;        }        else r--;    }    return ret;}void work(int now){    int v;    ans+=calc(now,0);    vis[now]=1;    for(int i=0;i<g[now].size();i++)    {        v=g[now][i].v;        if(!vis[v])        {            ans-=calc(v,g[now][i].l);            f[0]=nsiz=siz[v];            getroot(v,root=0);            work(root);        }    }}int main(){    int a,b,c;    scanf("%d",&n);    node tmp;    for(int i=1;i<n;i++)    {        scanf("%d%d%d",&a,&b,&c);        tmp.v=b;tmp.l=c;        g[a].pb(tmp);        tmp.v=a;tmp.l=c;        g[b].pb(tmp);    }    scanf("%d",&K);    f[0]=n;    getroot(1,root=0);    ans = 0;    work(root);    printf("%d\n", ans);    return 0;}


0 0
原创粉丝点击