• 【USACO18JAN】MooTube


    原文链接:https://blog.csdn.net/Patrickpwq/article/details/86656456

    给定一棵n个点的树(n=1e5),有边权,
    两点间距离定义为两点路径上的
    边权最小值。m个询问(m=1e5),k,v,
    询问对于点v,距离>=k的点有多少个(不含v)
    Input
    n个点,m个询问
    下面n-1行为边的信息
    下面m行
    ki和vi

    Output

    Sample Input
    7 4
    1 2 2
    1 3 1
    3 4 6
    3 5 5
    2 6 4
    2 7 3
    2 1
    4 3
    6 5
    10 7
    Sample Output
    3
    2
    0
    0

    标算是离线并查集 这里提供一种Kruskal重构树的简单做法

    将重构树建出来后 此时是一个小根堆

    我们倍增的往上跳 直到找到一个祖先的权值刚好小于K

    显然 这个祖先的子树内的所有点到v的距离都是大于等于K的 因为此时u到v的距离是LCA(u,v),而显然,LCA(u,v)一定属于这个祖先的子树

    #include<bits/stdc++.h>
    const int N=100005;
    using namespace std;
    template<class T>
    inline void read(T &x)
    {
    	x=0;
    	static char ch=getchar();
    	while(!isdigit(ch))	ch=getchar();
    	while(isdigit(ch))	x=x*10+ch-'0',ch=getchar();
    }
    int n,Q,cnt,first[2*N],tot,size[2*N];
    struct Edge
    {
    	int from,to,next,val;
    	bool operator <(const Edge &p) const
    	{
    		return this->val>p.val;
    	}
    }e[N],edge[8*N];
    inline void addedge(int x,int y)
    {
    	tot++;
    	edge[tot].to=y; edge[tot].next=first[x]; first[x]=tot;
    }
    int father[2*N],up[2*N][22],val[2*N],depth[2*N];
    inline int getfather(int x)
    {
    	if(father[x]==x)	return x;
    	return father[x]=getfather(father[x]);
    }
    void Kruskal_Rebuild()
    {
    	sort(e+1,e+cnt+1);
    	for(register int i=1;i<=2*n;i++)	father[i]=i;
    	int sign=n;
    	for(register int i=1;i<=cnt;i++)
    	{
    		int fx=getfather(e[i].from);		int fy=getfather(e[i].to);
    		if(fx==fy)	continue;
    		father[fx]=father[fy]=++sign;
    		addedge(fx,sign); addedge(sign,fx);
    		addedge(fy,sign); addedge(sign,fy);
    		val[sign]=e[i].val;
    	}
    }
    void dfs(int now,int fa)
    {
    	if(now<=n)	size[now]=1;
    	depth[now]=depth[fa]+1;
    	up[now][0]=fa;
    	for(int i=1;i<=19;i++)	up[now][i]=up[up[now][i-1]][i-1];
    	for(int u=first[now];u;u=edge[u].next)
    	{
    		int vis=edge[u].to;
    		if(vis==fa)	continue;
    		dfs(vis,now);
    		size[now]+=size[vis];
    	}
    }
    int main()
    {
    	cin>>n>>Q;
    	for(register int i=1;i<=n-1;i++)
    	{
    		int x,y,z;
    		read(x); read(y); read(z);
    		e[++cnt].from=x; e[cnt].to=y; e[cnt].val=z; 
    	}
    	Kruskal_Rebuild();
    	dfs(2*n-1,0);
    	while(Q--)
    	{
    		int v,k;
    		read(k); read(v);
    		for(int i=19;i>=0;i--)
    			if(val[up[v][i]]>=k)	v=up[v][i];
    		cout<<size[v]-1<<'\n';
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    JAVA 桥接模式
    字模生成/提取原理
    const修饰指针
    BMP格式分析
    [转载]在.Net中使用SMTP发送邮件
    [转载]MD5加密解密
    四十二。java
    四十四。java
    四十一。复习第十二章内容
    三十六。文件流
  • 原文地址:https://www.cnblogs.com/cutemush/p/11781247.html
Copyright © 2020-2023  润新知