NOI模拟:第k大(点分治)

题意:
给一颗边带权的数,对于每一个点有 ki ,求从每个点出发第 ki 远的距离。

题解:
点分治。
建出点分树并在每一个节点储存管辖区域的距离,在每一个儿子节点记录对父亲的贡献,查询每一个点时二分,再暴力爬树高验证可行性就好了。

#include<bits/stdc++.h>
using namespace std;
struct 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');}
    }
}io;
const int Maxn=1e4+50;
typedef pair<int,int> pii;
int n,k[Maxn],rt,dfn[Maxn],id[Maxn],dis[Maxn],sze[Maxn],vis[Maxn],ind,mx,total,G,lim,Ans[Maxn];
int mn[Maxn*2][18],cnt,Log[Maxn*2],mnpos[Maxn];
int nowfa[Maxn];
vector<pii>edge[Maxn];
vector<int>len[Maxn];
vector<int>LenToFa[Maxn];
inline void dfs(int now,int f,int dist=0)
{
    dis[now]=dis[f]+dist;
    id[dfn[now]=++ind]=now;
    mn[++cnt][0]=dfn[now];
    mnpos[now]=cnt;
    for(int e=edge[now].size()-1;e>=0;e--)
    {
        int v=edge[now][e].first,w=edge[now][e].second;
        if(v==f)continue;
        dfs(v,now,w);
        mn[++cnt][0]=dfn[now];
    }
}
inline void calcG(int now,int f)
{
    sze[now]=1;int nowmx=0;
    for(int e=edge[now].size()-1;e>+0;e--)
    {
        int v=edge[now][e].first;
        if(v==f||vis[v])continue;
        calcG(v,now);
        sze[now]+=sze[v];
        nowmx=max(nowmx,sze[v]);
    }
    nowmx=max(nowmx,total-sze[now]);
    if(nowmx<mx)mx=nowmx,G=now;
}
inline void getsze(int now,int f)
{
    sze[now]=1;
    for(int e=edge[now].size()-1;e>=0;e--)
    {
        int v=edge[now][e].first;
        if(v==f||vis[v])continue;
        getsze(v,now);
        sze[now]+=sze[v];
    }
}
inline void getdep(int fa,int g,int now,int dist,int f)
{
    len[fa].push_back(dist);LenToFa[g].push_back(dist);
    for(int e=edge[now].size()-1;e>=0;e--)
    {
        int v=edge[now][e].first,w=edge[now][e].second;
        if(vis[v]||v==f)continue;
        getdep(fa,g,v,dist+w,now);
    }
}
inline void work(int now)
{
    vis[now]=1;
    len[now].push_back(0);
    for(int e=edge[now].size()-1;e>=0;e--)
    {
        int v=edge[now][e].first,w=edge[now][e].second;
        if(vis[v])continue;
        getsze(v,now);
        total=mx=sze[v];
        calcG(v,now);
        getdep(now,G,v,w,now);
        nowfa[G]=now;
        work(G);
    }
    sort(len[now].begin(),len[now].end());
    sort(LenToFa[now].begin(),LenToFa[now].end());
}
inline void SplitTree()
{
    mx=total=n;
    calcG(1,0);
    rt=G;
    work(G);
}
inline int getlca(int x,int y)
{
    int a=mnpos[x],b=mnpos[y];
    if(a>b)swap(a,b);
    return id[min(mn[a][Log[b-a]],mn[b-(1<<Log[b-a])+1][Log[b-a]])];
}
inline int getdis(int a,int b)
{
    int lca=getlca(a,b);
    return dis[a]+dis[b]-2*dis[lca];
}
inline int getans(int x,int length)
{
    int last=0,ans=0,now=x;
    while(now)
    {
        int dist=getdis(now,x);
        ans+=upper_bound(len[now].begin(),len[now].end(),length-dist)-len[now].begin();
        if(last)ans-=upper_bound(LenToFa[last].begin(),LenToFa[last].end(),length-dist)-LenToFa[last].begin();
        last=now;
        now=nowfa[now];
    }
    return ans;
}
int main()
{
    io.init();
    n=io.read();
    for(int i=1;i<n;i++)
    {
        int x=io.read(),y=io.read(),z=io.read();
        edge[x].push_back(make_pair(y,z));
        edge[y].push_back(make_pair(x,z));
        lim+=z;
    }
    for(int i=1;i<=n;i++)k[i]=io.read();
    dfs(1,0);
    for(int i=2;i<=cnt;i++)Log[i]=Log[i>>1]+1;
    for(int j=1;j<=15;j++)
         for(int i=1;i<=cnt&&i+(1<<j)-1<=cnt;i++)
            mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
    SplitTree();
    for(int i=1;i<=n;i++)
    {
        int l=0,r=lim,ans=0;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(getans(i,mid)>=k[i])ans=mid,r=mid-1;
            else l=mid+1;
        }
        Ans[i]=ans;
    }
    for(int i=1;i<=n;i++)io.W(Ans[i]),io.ob->sputc('\n');
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值