[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;
}

原文地址:https://www.cnblogs.com/GoldenPotato/p/10210756.html

时间: 2024-07-31 22:27:29

[Luogu P4178]Tree (点分治+splay)的相关文章

luogu P4178 Tree

传送门 板子ex 开始天真的以为把m组询问改成k组询问就行了 但是板子里面的两层循环求方案实在是接受不了 所以套一个树状数组统计答案就行 注意大于k的边权全都不要 Code: 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define ms(a,b) memset(a,b,sizeof a) 5 #define rep(i,a,n) for(int i = a;i <= n;i++)

[LeetCode] Convert Sorted List to Binary Search Tree(分治)

Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST. 方法:为了使BST高度平衡,要找链表中的中值作为当前根节点. /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) :

poj 1744 tree 树分治

Tree Time Limit: 1000MS   Memory Limit: 30000K       Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an integer k,for every pair (u,v) of ve

POJ 1741 Tree ——点分治

[题目分析] 这貌似是做过第三道以Tree命名的题目了. 听说树分治的代码都很长,一直吓得不敢写,有生之年终于切掉这题. 点分治模板题目.自己YY了好久才写出来. 然后1A了,开心o(* ̄▽ ̄*)ブ [代码] #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define maxn 20005 #define inf 0x3f3f3f3f using

【BZOJ2870】最长道路tree 点分治+树状数组

[BZOJ2870]最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来往,所以每个路口i都有一个拥挤程度v[i],我们认为从路口s走到路口t的痛苦程度为s到t的路径上拥挤程度的最小值,乘上这条路径上的路口个数所得的积.现在请你求出痛苦程度最大的一条路径,你只需输出这个痛苦程度. 简化版描述: 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积

【BZOJ-1468】Tree 树分治

1468: Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1025  Solved: 534[Submit][Status][Discuss] Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k Output 一行,有多少对点之间的距离小于等于k Sample Input 7 1 6 13 6

HDU 4812 D Tree 树分治+逆元处理

D Tree Problem Description There is a skyscraping tree standing on the playground of Nanjing University of Science and Technology. On each branch of the tree is an integer (The tree can be treated as a connected graph with N vertices, while each bran

【CodeForces】914 E. Palindromes in a Tree 点分治

[题目]E. Palindromes in a Tree [题意]给定一棵树,每个点都有一个a~t的字符,一条路径回文定义为路径上的字符存在一个排列构成回文串,求经过每个点的回文路径数.n<=2*10^5. [算法]点分治 [题解]状压20位的二进制表示一条路径的字符状态,点分治过程中维护扫描过的路径只须维护状态桶数组,t[i]表示前面状态为i的路径条数. 合并:考虑当前状态为j,要使合并的状态满足条件即i^j=1<<k(0<=k<20)或i^j=0,移项得i=j^(1<

【Luogu】P3806点分治模板(点分治)

题目链接 wc听不懂lca讲的高等数学专场(一个字都听不懂),然后就自学了点分治. 点分治就是我先处理完跟根有关的东西,然后把根标记掉,把原树拆成若干个联通块,然后分别对每个联通块(每个小树)搞一模一样的操作. 然后要每次求重心,因为点分治复杂度跟递归深度有关. 本题判断的时候偷懒用map,其实自己写的splay也快不到哪里去的样子.qwq. #include<cstdio> #include<algorithm> #include<cstring> #include&