bzoj 1468(点分治)

来源:互联网 发布:麒麟655支持5g网络 编辑:程序博客网 时间:2024/05/30 04:49

传送门
最裸的点分治。此处不再附讲解,仅作模板使用。
注意:当前子树节点总数sum不要直接赋为siz[v]!(理论上说这样是不对的因为,siz[v]是上一次遍历的得到的子树节点个数,可能包括不在当前子树内的节点。但是后来发现这样直接赋值也不会造成干扰,因为要偏大,大家都偏大。整体偏大也不会影响找重心。) 以上说的纯属*话,有严重漏洞。事实证明有些数据强的题中,getdis( )必须再求一次siz(代码中已标明strongly advised to do so),确保打”!!!”标记处的siz和mx是关于当前子树的而非全树的,从而确保当前子树的重心找准。这个东西简直就是一个定时炸弹,强烈建议读者想清楚,如有需要可私信本人。

#include<bits/stdc++.h>using namespace std;const int MAXN=4e4+5,INF=0x3f3f3f3f;int n,k;int head[MAXN],edge=0;struct EDGE {    int v,nxt,w;}e[MAXN<<1];bool vis[MAXN];int siz[MAXN],mx[MAXN],dis[MAXN],sum,root=0;int a[MAXN],tot=0,ans=0;inline int read() {    int x=0,f=1;char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();    return x*f;}inline void adde(int u,int v,int w) {    e[edge].nxt=head[u],e[edge].v=v,e[edge].w=w,head[u]=edge++;    e[edge].nxt=head[v],e[edge].v=u,e[edge].w=w,head[v]=edge++;}void getroot(int p,int fa) {    siz[p]=1,mx[p]=0;    for (int i=head[p];~i;i=e[i].nxt) {        int v=e[i].v;        if (vis[v]||v==fa) continue;        getroot(v,p);        siz[p]+=siz[v];        mx[p]=max(mx[p],siz[v]);     }    mx[p]=max(mx[p],sum-siz[p]);    if (mx[p]<mx[root]) root=p;}void getdis(int p,int fa) {    siz[p]=1,a[++tot]=dis[p];    for (int i=head[p];~i;i=e[i].nxt) {        int v=e[i].v;        if (vis[v]||v==fa) continue;        dis[v]=dis[p]+e[i].w;        getdis(v,p);        siz[p]+=siz[v];//strongly advised to do so    }}inline int cal(int pos,int w) {    int sum=0;    dis[pos]=w,tot=0;    getdis(pos,0);    sort(a+1,a+tot+1);    for (int l=1,r=tot;l<r;)        a[l]+a[r]<=k?sum+=r-l,++l:--r;    return sum;}void work(int p) {    ans+=cal(p,0);    vis[p]=true;    for (int i=head[p];~i;i=e[i].nxt) {        int v=e[i].v;        if (!vis[v]) {            ans-=cal(v,e[i].w);            sum=siz[v];//!!!            root=0;            getroot(v,0);            work(root);        }    }}int main() {//  freopen("bzoj 1468.in","r",stdin);    memset(vis,false,sizeof(vis));    memset(head,-1,sizeof(head));    n=read();    for (register int i=1;i<n;++i) {        int u=read(),v=read(),w=read();        adde(u,v,w);    }    k=read();    sum=n;    mx[0]=INF;    getroot(1,0);    work(root);    printf("%d\n",ans);    return 0;}