zoukankan      html  css  js  c++  java
  • Gym

    题目传送门

    题目大意:

          给出一颗树,每条边都有一个颜色,对一个点来说,如果其他所有点到这个点的简单路径,相连的边颜色都不同,这个点即合法点,统计所有的合法点。

    思路:

          对于一个节点来说

          1、如果这个节点的两个子节点的边颜色一样,那么这两个子节点的子树都要放弃。

          2、如果这个节点的子节点和他的父节点的边的颜色一样,那么子节点所在子树放弃,父节点中除了这个节点以外的其他节点都要放弃。

    剩下的点就是合法点。

          那怎么做到放弃呢?

          先dfs处理出每个节点的dfs序,每个dfs序对应的节点标号,每个节点的子树大小(包括本身),对于第一种情况来说,dfs序在  子树节点dfs序  到 子树节点dfs序加上子树大小  这个左闭右开的区间都要放弃,则用一个数组,左边界加一,右边界减一。

    对于第二种情况,放弃的子节点和上述一样处理,父节点就要放弃  dfs序从1到父节点dfs序,父节点dfs序+1到最后所有的点,则对应位置加一或者减一,最后vis[ i ]=vis[ i  -1 ] + arr[ i ].处理完后,vis还等于0的点,就是合法的dfs序,找到这个dfs序对应的节点就可以了(dfs的时候就记录过了,大佬说这个做法叫差分约束)。

    这题五万个点,每个点三个数据,用读入优化居然没有快,,,可能是我的读入优化还不够优秀吧。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<string.h>
    #include<sstream>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<bitset>
    #define CLR(a,b) memset((a),(b),sizeof((a))) 
    using namespace std;
    typedef long long ll;
    inline int rd() {
    	int f = 1; int x = 0; char s = getchar();
    	while (s<'0' || s>'9') { if (s == '-')f = -1; s = getchar(); }
    	while (s >= '0'&&s <= '9') { x = x * 10 + s - '0'; s = getchar(); }x *= f;
    	return x;
    }
    int n;
    struct edge {
    	int v, color;
    	edge(){}
    	edge(int v,int color): v(v),color(color){}
    	
    };
    bool cmp(edge &a, edge &b)
    {
    	return a.color < b.color;
    }
    const int maxn = 50010;
    vector<edge >g[maxn];
    int arr[maxn], fa[maxn], son[maxn], dfn[maxn],tot,cnt,vis[maxn],dir[maxn];
    void dfs(int u, int pre)
    {
    	fa[u] = pre;
    	son[u] = 1;
    	dfn[u] = ++cnt;
    	dir[cnt] = u;
    	for (auto it : g[u])
    	{
    		if (it.v == pre)continue;
    		dfs(it.v, u);
    		son[u] += son[it.v];
    	}
    }
    int main() {
    	cin >> n;
    	for (int i = 1; i < n; i++)
    	{
    		int u, v, color;
    		u = rd(), v = rd(), color = rd();
    		//scanf("%d%d%d", &u, &v, &color);
    		g[u].push_back(edge(v, color));
    		g[v].push_back(edge(u, color));
    	}
    	dfs(1, 0);
    	for (int i = 1; i <= n; i++)
    	{
    		sort(g[i].begin(), g[i].end(), cmp);
    		int si = g[i].size();
    		for (int j = 0; j < si - 1; j++)
    		{
    			if (g[i][j].color == g[i][j + 1].color)
    			{
    				
    				int x = g[i][j].v, y = g[i][j+1].v;
    				if (fa[x] == i && fa[y] == i)
    				{
    					
    					arr[dfn[x]]++;
    					arr[dfn[x] + son[x]]--;
    					arr[dfn[y]]++;
    					arr[dfn[y] + son[y]]--;
    				}
    				else if (fa[x] == i && fa[i] == y)
    				{
    					
    					arr[dfn[x]]++;
    					arr[dfn[x] + son[x]]--;
    					arr[dfn[1]]++;
    					arr[dfn[i]]--;
    					arr[dfn[i] + son[i]]++;
    				}
    				else if (fa[y] == i && fa[i] == x)
    				{
    					swap(x, y);
    					arr[dfn[x]]++;
    					arr[dfn[x] + son[x]]--;
    					arr[dfn[1]]++;
    					arr[dfn[i]]--;
    					arr[dfn[i] + son[i]]++;
    				}
    			}
    		}
    	}
    	for (int i = 1; i <= n; i++)
    	{
    		vis[i] = vis[i - 1] + arr[i];
    	}
    	vector<int >ans;
    	for (int i = 1; i <= n; i++)
    	{
    		if (vis[i] == 0)
    		{
    			tot++;
    			ans.push_back(dir[i]);
    		}
    	}
    	printf("%d
    ", tot);
    	sort(ans.begin(), ans.end());
    	for (auto it : ans)
    	{
    		printf("%d
    ", it);
    	}
    }
    

      

  • 相关阅读:
    fusioncompute安装虚拟机的问题---如何扩容至5T 和 挂载Tools的解决方式
    接口请求返回状态码总结
    【内推】字节跳动
    RPA行业见解(一)
    消息中间件(一)MQ详解及四大MQ比较
    Springcloud学习
    常用加密算法
    Java实现token的生成与验证
    linux 系统下安装和卸载Node.js
    Linux安装Mysql
  • 原文地址:https://www.cnblogs.com/mountaink/p/9553389.html
Copyright © 2011-2022 走看看