zoukankan      html  css  js  c++  java
  • 【bzoj1316】树上的询问 树的点分治+STL-set

    题目描述

    一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No.

    输入

    第一行两个整数n, p分别表示点的个数和询问的个数. 接下来n-1行每行三个数x, y, c,表示有一条树边x→y,长度为c. 接下来p行每行一个数Len,表示询问树中是否存在一条长度为Len的路径.

    输出

    输出有p行,Yes或No.

    样例输入

    6 4
    1 2 5
    1 3 7
    1 4 1
    3 5 2
    3 6 3
    1
    8
    13
    14

    样例输出

    Yes
    Yes
    No
    Yes


    题解

    树的点分治+STL-set

    由于有多组询问,所以可以考虑把询问离线,然后一起处理(貌似暴力也能过)。

    然后就是点分治的经典题目了。

    每次找子树是查询以前的某深度与现在的某深度形成的路径长度是否为l。这个可以使用set维护。

    时间复杂度$O(nqlog^2n)=O(能过)$。

    #include <set>
    #include <cstdio>
    #define N 10010
    using namespace std;
    set<int> s;
    int m , a[N] , head[N] , to[N << 1] , len[N << 1] , next[N << 1] , cnt , si[N] , mx[N] , sum , root , deep[N] , vis[N] , d[N] , tot;
    bool ans[N];
    void add(int x , int y , int z)
    {
    	to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
    }
    void getroot(int x , int fa)
    {
    	int i;
    	si[x] = 1 , mx[x] = 0;
    	for(i = head[x] ; i ; i = next[i])
    		if(!vis[to[i]] && to[i] != fa)
    			getroot(to[i] , x) , si[x] += si[to[i]] , mx[x] = max(mx[x] , si[to[i]]);
    	mx[x] = max(mx[x] , sum - si[x]);
    	if(mx[x] < mx[root]) root = x;
    }
    void dfs(int x , int fa)
    {
    	int i;
    	si[x] = 1 , d[++tot] = deep[x];
    	for(i = head[x] ; i ; i = next[i])
    		if(!vis[to[i]] && to[i] != fa)
    			deep[to[i]] = deep[x] + len[i] , dfs(to[i] , x) , si[x] += si[to[i]];
    }
    void solve(int x)
    {
    	int i , j , k;
    	vis[x] = 1 , s.clear() , s.insert(0);
    	for(i = head[x] ; i ; i = next[i])
    	{
    		if(!vis[to[i]])
    		{
    			tot = 0 , deep[to[i]] = len[i] , dfs(to[i] , 0);
    			for(j = 1 ; j <= tot ; j ++ )
    				for(k = 1 ; k <= m ; k ++ )
    					if(s.find(a[k] - d[j]) != s.end())
    						ans[k] = 1;
    			for(j = 1 ; j <= tot ; j ++ ) s.insert(d[j]);
    		}
    	}
    	for(i = head[x] ; i ; i = next[i])
    		if(!vis[to[i]])
    			sum = si[to[i]] , root = 0 , getroot(to[i] , 0) , solve(root);
    }
    int main()
    {
    	int n , i , x , y , z;
    	scanf("%d%d" , &n , &m);
    	for(i = 1 ; i < n ; i ++ ) scanf("%d%d%d" , &x , &y , &z) , add(x , y , z) , add(y , x , z);
    	for(i = 1 ; i <= m ; i ++ )
    	{
    		scanf("%d" , &a[i]);
    		if(!a[i]) ans[i] = 1;
    	}
    	mx[0] = 1 << 30 , sum = n , getroot(1 , 0) , solve(root);
    	for(i = 1 ; i <= m ; i ++ ) printf("%s
    " , ans[i] ? "Yes" : "No");
    	return 0;
    }
    

     

  • 相关阅读:
    【网络对抗技术】20181234 Exp6 MSF应用基础
    2018-2019-1 20189229 《Linux内核原理与分析》第九周作业
    2018-2019-1 20189229 《Linux内核原理与分析》第八周作业
    2018-2019-1 20189229 《Linux内核原理与分析》第七周作业
    2018-2019-1 20189229《Linux内核原理与分析》第六周作业
    2018-2019-1 20189229 《Linux内核原理与分析》第五周作业
    20189229 张子松 第四周作业
    2018-2019-1 20189229《Linux内核原理与分析》第三周作业
    20189229 张子松 第二周作业
    《Linux内核原理与分析》第一周作业
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7481768.html
Copyright © 2011-2022 走看看