• 【BZOJ4317】Atm的树 动态树分治+二分+线段树


    【BZOJ4317】Atm的树

    Description

    Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree……
    于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的点有一个距离(什么是距离不用说吧),他需要对于每个点回答:从这个点出发的第k小距离是多少;
    如果atm不能回答出来,那么明天4019的闹钟将不会响,4019全寝可能就迟到了,所以atm希望你帮帮他。

    Input

    第一行,两个正整数n,k,表示树的点数,询问的是第几小距离;
    第二~n行,每行三个正整数x,y,w,表示x和y之间有一条边,x为父亲,边权为w;

    Output

    n行, 每行一个数,第i行输出从i开始第k小距离

    Sample Input

    5 2
    1 5 2
    1 2 4
    2 3 6
    2 4 5

    Sample Output

    4
    5
    10
    9
    6

    HINT

    100% n<=15000, 边权在1~10之间,为了方便,保证1为根;K<=5000

    题解:依旧是动态点分治。

    统计第k大不太好搞,我们对于每个点都二分一下,变成求到一个点距离<=mid的点有多少个,然后就变成熟悉的题了。

    我们对于每个点维护一棵线段树,记录它在点分树的子树中有多少个点到它的距离为x,同时为了去重,还要维护一个从它父亲中减去的版本。

    时间复杂度$O(nlog_n^3)$。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int maxn=15010;
    int n,m,N,tot,cnt,rt,mn;
    int to[maxn<<1],next[maxn<<1],head[maxn],val[maxn<<1],siz[maxn],fa[maxn],md[20][maxn<<1],pos[maxn],vis[maxn];
    int Log[maxn<<1],dep[maxn],r1[maxn],r2[maxn];
    struct sag
    {
    	int ls,rs,siz;
    }s[maxn*100];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    inline void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    }
    void getrt(int x,int fa)
    {
    	int tmp=0,i;
    	siz[x]=1;
    	for(i=head[x];i!=-1;i=next[i])	if(!vis[to[i]]&&to[i]!=fa)
    		getrt(to[i],x),tmp=max(tmp,siz[to[i]]),siz[x]+=siz[to[i]];
    	tmp=max(tmp,tot-siz[x]);
    	if(tmp<mn)	mn=tmp,rt=x;
    }
    void dfs(int x)
    {
    	pos[x]=++pos[0],md[0][pos[0]]=dep[x];
    	for(int i=head[x];i!=-1;i=next[i])	if(!dep[to[i]])	dep[to[i]]=dep[x]+val[i],dfs(to[i]),md[0][++pos[0]]=dep[x];
    }
    void solve(int x)
    {
    	vis[x]=1;
    	for(int i=head[x];i!=-1;i=next[i])	if(!vis[to[i]])
    		tot=siz[to[i]],mn=1<<30,getrt(to[i],x),fa[rt]=x,solve(rt);
    }
    inline int dis(int x,int y)
    {
    	int a=pos[x],b=pos[y];
    	if(a>b)	swap(a,b);
    	int k=Log[b-a+1];
    	return dep[x]+dep[y]-2*min(md[k][a],md[k][b-(1<<k)+1]);
    }
    void insert(int l,int r,int &x,int a)
    {
    	if(!x)	x=++tot;
    	s[x].siz++;
    	if(l==r)	return ;
    	int mid=(l+r)>>1;
    	if(a<=mid)	insert(l,mid,s[x].ls,a);
    	else	insert(mid+1,r,s[x].rs,a);
    }
    int query(int l,int r,int x,int a,int b)
    {
    	if(a>b)	return 0;
    	if(!x||(a<=l&&r<=b))	return s[x].siz;
    	int mid=(l+r)>>1;
    	if(b<=mid)	return query(l,mid,s[x].ls,a,b);
    	if(a>mid)	return query(mid+1,r,s[x].rs,a,b);
    	return query(l,mid,s[x].ls,a,b)+query(mid+1,r,s[x].rs,a,b);
    }
    inline int calc(int x,int mid)
    {
    	int ret=0,y,z;
    	for(y=x;y;y=z)
    	{
    		z=fa[y];
    		if(z)	ret-=query(0,N,r2[y],0,mid-dis(x,z));
    		ret+=query(0,N,r1[y],0,mid-dis(x,y));
    	}
    	return ret;
    }
    int main()
    {
    	n=rd(),m=rd()+1;
    	int i,j,u,v,a,b,c,l,r,mid;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<n;i++)	a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c),N+=c;
    	dep[1]=1,dfs(1),tot=n,mn=1<<30,getrt(1,0),solve(rt);
    	for(i=2;i<(n<<1);i++)	Log[i]=Log[i>>1]+1;
    	for(j=1;(1<<j)<(n<<1);j++)	for(i=1;i+(1<<j)-1<(n<<1);i++)	md[j][i]=min(md[j-1][i],md[j-1][i+(1<<(j-1))]);
    	for(i=1;i<=n;i++)
    	{
    		for(u=i;u;u=v)
    		{
    			v=fa[u];
    			if(v)	insert(0,N,r2[u],dis(i,v));
    			insert(0,N,r1[u],dis(i,u));
    		}
    	}
    	for(i=1;i<=n;i++)
    	{
    		l=0,r=N+1;
    		while(l<r)
    		{
    			mid=(l+r)>>1;
    			if(calc(i,mid)>=m)	r=mid;
    			else	l=mid+1;
    		}
    		printf("%d
    ",r);
    	}
    	return 0;
    }
  • 相关阅读:
    python判断语句和循环语句
    Web项目如何做单元测试
    PHP接口自动化测试框架实现
    引入缺陷的原因都有哪些?
    测试基础:(一)
    测试基础(二)
    测试术语2
    测试术语3
    测试术语4
    Spring Cloud Stream与Spring Cloud Bus区别?
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7747239.html
Copyright © 2020-2023  润新知