BZOJ3572: [Hnoi2014]世界树(虚树)

news/2024/7/23 23:49:03 标签: 虚树, dp

传送门

题意:
一棵树,每次给k个控制点,求每个控制点能控制几个点。(一个点被离它最近的控制点控制)。

题解:
虚树
首先建出虚树,考虑怎么dp

首先要dp出离每个虚树上的点最近的点。
dp两次即可。一次找子树,一次找父亲。

其次,对于虚树的根节点,根节点以外的其他所有不在虚树中的点被离虚树中的根节点最近的点控制。

对于虚树中的任意一条路径,倍增求出原树种这条路径上离现在的点最近的点。如果这条路径两边从属一样,那么直接加上即可。

如果不一样,需要倍增查找分界点(一半从属下面,一半从属上面)。分别累加。

对于不在虚树中的子树,大小为该点的子树大小减去虚树中最近点的子树大小。

  • Code
#include<bits/stdc++.h>
using namespace std;
namespace IO
{
    streambuf *ib,*ob;int buf[50];
    inline void init()
    {
        ios::sync_with_stdio(false);
        cin.tie(NULL);cout.tie(NULL);
        ib=cin.rdbuf();ob=cout.rdbuf();
    }
    inline int read()
    {
        char ch=ib->sbumpc();int i=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=ib->sbumpc();}
        while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=ib->sbumpc();}
        return i*f;
    }
    inline void W(int x)
    {
        if(!x){ob->sputc('0');return;}
        if(x<0){ob->sputc('-');x=-x;}
        while(x){buf[++buf[0]]=x%10;x/=10;}
        while(buf[0])ob->sputc(buf[buf[0]--]+'0');
    }
}

const int Maxn=3e5+50;
int n,m,rt,q,vt,dfn[Maxn],ind,dep[Maxn],sze[Maxn],fa[Maxn][20],vir[Maxn],id[Maxn],dis[Maxn],belong[Maxn],ans[Maxn];
vector<int>edge[Maxn];
vector<int>nowedge[Maxn];
inline int getlca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    if(dep[x]!=dep[y])
    {
        int b=dep[x]-dep[y];
        for(int i=0;i<=18&&b;i++)
        {
            if(b&1)x=fa[x][i];
            b>>=1;
        }
    }
    if(x==y)return x;
    for(int i=18;i>=0;i--)
    {
        if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
    }
    return fa[x][0];
}
inline void dfs(int now,int f)
{
    dep[now]=dep[f]+1;sze[now]=1;fa[now][0]=f;dfn[now]=++ind;
    for(int i=1;i<=18;i++)fa[now][i]=fa[fa[now][i-1]][i-1];
    for(int e=edge[now].size()-1;e>=0;e--)
    {
        int v=edge[now][e];
        if(v==f)continue;
        dfs(v,now);sze[now]+=sze[v];
    }
}
inline bool compdfn(const int &a,const int &b){return  dfn[a]<dfn[b];}
inline void BuildAuxTree()
{
    static int a[Maxn],nowfa[Maxn],cnt,sta[Maxn],top;
    cnt=m=IO::read();++vt;top=0;
    for(int i=1;i<=m;i++)a[i]=vir[i]=IO::read(),id[vir[i]]=vt,ans[a[i]]=0;
    sort(a+1,a+m+1,compdfn);
    for(int i=1;i<=m;i++)
    {
        if(!top)
        {
            rt=a[i];
            nowfa[a[i]]=0;
            sta[++top]=a[i];
            continue;
        }
        int lca=getlca(a[i],sta[top]);
        if(lca!=sta[top])
        {
            while(dep[sta[top]]>dep[lca])
            {
                if(dep[sta[top-1]]<dep[lca])nowfa[sta[top]]=lca;
                top--;
            }
            if(lca!=sta[top])
            {
                if(!top)rt=lca;
                a[++cnt]=lca;
                nowfa[lca]=sta[top];
                sta[++top]=lca;
            }
        }
        nowfa[a[i]]=sta[top];
        sta[++top]=a[i];
    }
    for(int i=1;i<=cnt;i++)nowedge[a[i]].clear();
    for(int i=1;i<=cnt;i++)nowedge[nowfa[a[i]]].push_back(a[i]);
}
inline void FindClose1(int now,int f)
{
    if(id[now]==vt)dis[now]=0,belong[now]=now;
    else dis[now]=n+1,belong[now]=n+1;
    for(int e=nowedge[now].size()-1;e>=0;e--)
    {
        int v=nowedge[now][e];
        if(v==f)continue;
        FindClose1(v,now);
        int len=dep[v]-dep[now];
        if(dis[now]>dis[v]+len)dis[now]=dis[v]+len,belong[now]=belong[v];
        else if(dis[now]==dis[v]+len&&belong[now]>belong[v])belong[now]=belong[v];
    }
}
inline void FindClose2(int now,int f,int dist)
{
    if(now!=rt)
    {
        if(dis[f]+dist<dis[now])dis[now]=dis[f]+dist,belong[now]=belong[f];
        else if(dis[f]+dist==dis[now]&&belong[now]>belong[f])belong[now]=belong[f];
    }
    for(int e=nowedge[now].size()-1;e>=0;e--)
    {
        int v=nowedge[now][e];
        if(v==f)continue;
        FindClose2(v,now,dep[v]-dep[now]);
    }
}
inline int GetClosest(int x,int y)
{
    for(int i=18;i>=0;i--)
        if(dep[fa[x][i]]>dep[y])x=fa[x][i];
    return x;
}
inline void GetAns(int now,int f)
{
    if(now==rt)ans[belong[now]]+=sze[1]-sze[now];
    int w=sze[now];
    for(int e=nowedge[now].size()-1;e>=0;e--)
    {
        int v=nowedge[now][e];
        if(v==f)continue;
        int suf=GetClosest(v,now);
        w-=sze[suf];
        if(belong[v]==belong[now])ans[belong[now]]+=(sze[suf]-sze[v]);
        else
        {
            int suf2=v;
            for(int i=18;i>=0;i--)
            {
                if(dep[fa[suf2][i]]>dep[now])
                {
                    if(dep[v]-dep[fa[suf2][i]]+dis[v]<dep[fa[suf2][i]]-dep[now]+dis[now])suf2=fa[suf2][i];
                    else if((dep[v]-dep[fa[suf2][i]]+dis[v]==dep[fa[suf2][i]]-dep[now]+dis[now])&&(belong[v]<belong[now]))suf2=fa[suf2][i];
                }
            }
            ans[belong[now]]+=sze[suf]-sze[suf2];
            ans[belong[v]]+=sze[suf2]-sze[v];
        }
        GetAns(v,now);
    }
    ans[belong[now]]+=w;
}
int main()
{
    IO::init();n=IO::read();
    for(int i=1;i<n;i++)
    {
        int x=IO::read(),y=IO::read();
        edge[x].push_back(y);edge[y].push_back(x);
    }
    dfs(1,0);
    q=IO::read();
    while(q--)
    {
        BuildAuxTree();
        FindClose1(rt,0);
        FindClose2(rt,0,0);
        GetAns(rt,0);
        for(int i=1;i<=m;i++)IO::W(ans[vir[i]]),IO::ob->sputc(' ');
        IO::ob->sputc('\n');
    }
}

http://www.niftyadmin.cn/n/1726057.html

相关文章

Jupyter notebook使用

1.介绍 其为python代码文件生成和生成笔记文本的实用工具,能生成.md文件,适合python教学、python开发。下面开启Jupyter notebook的使用。 2.下载 安装anacomda3,打开home,里面有Jupyter notebook的install 的窗口。 3.使用 点开Jupyter notebook,选择一个浏览器,创建自己…

SPOJ104:Highways(矩阵树定理)

关于矩阵树定理的证明&#xff1a;https://wenku.baidu.com/view/872eb02de2bd960590c677c6.html (对了 高斯消元记得判无解) #include<bits/stdc.h> using namespace std; const double eps1e-5; namespace IO {streambuf *ib,*ob;int buf[50];inline void init(){ios…

数字类型(python)

数字类型 1.1 常量数字 直接表示出来的数字&#xff0c;即常量 1.2 整数 整数通常指不带小数的数字&#xff0c;包括自然数&#xff0c;0&#xff0c;负数等&#xff0c;举例0&#xff0c;-34&#xff0c;2可以表示任意大的数&#xff0c;python区别其他编程语言&#xff0c…

poj1741:Tree(点分治模板)

传送门 题意&#xff1a; 求一颗树上长度不超过k的路径。 题解&#xff1a; 点分治模板。 #include<iostream> #include<vector> #include<algorithm> using namespace std; typedef pair<int,int> pii; streambuf *ib,*ob;inline int read() {ch…

ROI目标区域截取(Python/OpenCV)

问题&#xff1a;当进行目标检测&#xff0c;获取输出检测目标print( top, left, bottom, right)的左上顶点和右下顶点两个点坐标&#xff0c;怎么将目标区域截取下来&#xff1f; 首先提供我使用的原图&#xff1a; 下面针对于下方原图黄色方框中的车辆目标区域截取举例&…

torch.randn(50,512,7,7)

代码示例&#xff1a; import torch #生成50大组512小组二维7x7包含7x7x512x50个符合&#xff08;0,1&#xff09;正态分布的随机填充数 x1_intorch.randn(50,512,7,7) #生成一维包含两个符合&#xff08;0,1&#xff09;正态分布的随机填充数 x2_intorch.randn(2) #生成二维4…

yolov3、yolov4等批量预测图片并保存(python)

目录 说明方法一、按图片的文件夹获取图片路径二、按图片对应的txt文件夹获取图片路径说明 本批量预测图片代码很适用于深度学习目标检测当中,将代码主干添加到预测脚本当中,修改部分调用参数、读入文件夹、保存文件夹等都可适用,方法如下: 方法 一、按图片的文件夹获取…

【修改xml标注信息类别】【删除xml标注某几个类别】

使用python. xml解析树解析xml文件&#xff0c;批量修改xml文件里object节点下name节点的content,删除某几类内容。 代码展示&#xff1a; import glob import xml.etree.ElementTree as ET def change_xmlfile(path):i 0j 0new_name1car_suvnew_name2car_license_platenew_…