[Luogu P4178]Tree (点分治+splay)

Posted goldenpotato

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Luogu P4178]Tree (点分治+splay)相关的知识,希望对你有一定的参考价值。

题面

传送门:https://www.luogu.org/problemnew/show/P4178


Solution

首先,长成这样的题目一定是淀粉质跑不掉了。

考虑到我们不知道K的大小,我们可以开一个splay来统计比某个数小的数的数量。

 

具体做法等我开淀粉质讲解的坑再满满填(咕)

 


Code

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
long long read()
{
    long long x=0,f=1; char c=getchar();
    while(!isdigit(c)){if(c==-) f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-0;c=getchar();}
    return x*f;
}
const int N=40000+100;
struct road
{
    long long w;
    int to;
    road(int A,long long B)
    {
        to=A,w=B;
    }
};
struct SBT
{
    #define root son[0][1]
    int fa[N],son[N][2],w[N],size[N],cnt[N],to;
    inline void update(int now)
    {
        size[now]=size[son[now][0]]+size[son[now][1]]+cnt[now];
    }
    inline void rotate(int x,int type)
    {
        int y=fa[x],z=fa[y];
        fa[x]=z,son[z][y==son[z][1]]=x;
        son[y][!type]=son[x][type],fa[son[x][type]]=y;
        son[x][type]=y,fa[y]=x;
        update(y),update(x);
    }
    void splay(int now,int to)
    {
        while(fa[now]!=to)
        {
            if(now==son[fa[now]][fa[now]==son[fa[fa[now]]][1]] and fa[fa[now]]!=to)
                rotate(fa[now],now==son[fa[now]][0]),
                rotate(now,now==son[fa[now]][0]);
            else
                rotate(now,now==son[fa[now]][0]);
        }
    }
    inline void InitTree()
    {
        root=to=0;
    }
    inline void init(int now)
    {
        fa[now]=son[now][0]=son[now][1]=size[now]=w[now]=0;
    }
    void Insert(int num)
    {
        if(root==0)
        {
            root=++to;
            init(root);
            fa[root]=0;
            w[root]=num,cnt[root]=1,update(root);
            return;
        }
        int now=root,last=root;
        while(now!=0)
        {
            if(w[now]==num)
            {
                cnt[now]++;
                splay(now,0);
                return;
            }
            last=now,now=son[now][num>w[now]];
        }
        now=++to,init(now);
        w[now]=num,cnt[now]=1;
        fa[now]=last,son[last][num>w[last]]=now;
        update(now),splay(now,0);
    }
    int Query(int num)
    {
        int now=root,t_ans=0;
        while(now!=0)
        {
            if(num>=w[now])
            {
                if(w[now]>=w[t_ans]) t_ans=now;
                now=son[now][1];
            }
            else
                now=son[now][0];
        }    
        if(t_ans==0) return 0;
        splay(t_ans,0);
        return size[son[root][0]]+cnt[root];
    }
    #undef root
}sbt;
vector <road> e[N];
long long n,K;
bool vis[N],t_vis[N],done[N];
int size[N],cnt,root;
int GetSize(int now)
{
    t_vis[now]=true;
    size[now]=1;
    for(int i=0;i<int(e[now].size());i++)
        if(t_vis[e[now][i].to]==false and vis[e[now][i].to]==false)
            size[now]+=GetSize(e[now][i].to); 
    t_vis[now]=0;
    return size[now];
}
void GetRoot(int now)
{
    t_vis[now]=true,size[now]=1;
    bool OK=true;
    for(int i=0;i<int(e[now].size());i++)
        if(t_vis[e[now][i].to]==false and vis[e[now][i].to]==false)
        {
            GetRoot(e[now][i].to); 
            size[now]+=size[e[now][i].to];
            if(size[e[now][i].to]>cnt/2)
                OK=false;
        }
    if(cnt-size[now]>cnt/2)    OK=false;
    if(OK==true)    root=now;
    t_vis[now]=0;
}
int ans;
void dfs2(int now,long long dis,int type)
{
    t_vis[now]=true;
    if(type==1 and K-dis>=0)
        ans+=sbt.Query(K-dis);
    else if(type==2)
        sbt.Insert(dis);
    for(int i=0;i<int(e[now].size());i++)
        if(t_vis[e[now][i].to]==false and done[e[now][i].to]==true)
            dfs2(e[now][i].to,dis+e[now][i].w,type);
    t_vis[now]=false;
}
void dfs(int now)
{
    //cerr<<now<<endl;
    vis[now]=true;
    vector <road> son;
    for(int i=0;i<int(e[now].size());i++)
        if(vis[e[now][i].to]==false)
        {
            cnt=GetSize(e[now][i].to);
            GetRoot(e[now][i].to);
            son.push_back(e[now][i]);
            dfs(root);
        }
    sbt.InitTree();
    sbt.Insert(0);
    for(int i=0;i<int(son.size());i++)
        dfs2(son[i].to,son[i].w,1),dfs2(son[i].to,son[i].w,2);
    done[now]=true;
}
int main()
{
    freopen("4178.in","r",stdin);
    
    n=read();
    for(int i=1;i<=n;i++)
        e[i].reserve(4);
    for(int i=1;i<n;i++)
    {
        long long s=read(),t=read(),w=read();
        e[s].push_back(road(t,w));
        e[t].push_back(road(s,w));
    }
    K=read();

    cnt=GetSize(1);
    GetRoot(1);
    dfs(root);
    
    printf("%d",ans);
    return 0;
}

 

以上是关于[Luogu P4178]Tree (点分治+splay)的主要内容,如果未能解决你的问题,请参考以下文章

P4178 Tree (点分治)

P4178 Tree

luogu P4178 Tree

Luogu 4178Tree

Luogu2264 树上游戏(点分治)

[Luogu3806]点分治