zoukankan      html  css  js  c++  java
  • CF 570D Tree Requests

    题目大意

    在一棵以结点 (1) 为根的树上有 (n) 个结点,每个结点上有一个小写字母,每个点的深度定义为根结点到该结点路径上的点数。
    现在有 (m) 次询问 (a,b) ,要求输出以结点 (a) 为根的子树上深度为 (b) 的所有结点上的字母,重新排列后能否形成回文串。
    其中,(1 leq n leq 5 imes 10^5)(1 leq m leq 5 imes 10^5)

    题解

    显然对于深度相同且在同一子树中的结点,若字母形成回文串,那么最多只有 (1) 种字母的出现次数为奇数。
    因为只有 (26) 种字母,且每种字母的出现次数可以用 (0) / (1) 表示,所以我们可以用一个二进制数来表示每种字母出现的状态。

    然而观察到如果把每个结点 (v_i) 的每一个深度 (d_i) 的答案都统计下来,要开大小为 (n^2) 的数组,显然会 MLE,而且时间复杂度也很大。
    因此,我们可以先把查询记录下来,只记录查询的答案。

    剩下的很显然,直接用 dsu on tree 即可。对于每一个深度 (d_i) ,用一个数组 (vis(d_i)) 表示当前深度遍历到子树结点的字母状态。
    (vis(d_i) - operatorname{lowbit}left(visleft(d_i ight) ight) = 0) 时,显然答案为 ( exttt{Yes}) ,否则为 ( exttt{No})

    #include <cstdio>
    
    #define MAX_N (500000 + 5)
    #define MAX_M (500000 + 5)
    
    #define lowbit(x) ((x)&-(x))
    
    struct Node
    {
    	int dep;
    	int size;
    	int son;
    	int val;
    };
    
    struct Edge
    {
    	int to;
    	int next;
    };
    
    int n, m;
    char str[MAX_N];
    Node a[MAX_N];
    int h[MAX_N];
    Edge e[MAX_N];
    int hq[MAX_M];
    Edge q[MAX_M];
    int vis[MAX_N];
    bool ans[MAX_M];
    
    void Add_Edge(int, int, int);
    void Add_Query(int, int, int);
    void DFS1(int);
    void DFS2(int);
    void DSU(int, bool);
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	int u, v;
    	for (int i = 2; i <= n; ++i)
    	{
    		scanf("%d", &u);
    		Add_Edge(u, i, i - 1);
    	}
    	scanf("%s", str + 1);
    	for (int i = 1; i <= n; ++i)
    	{
    		a[i].val = 1 << str[i] - 'a';
    	}
    	for (int i = 1; i <= m; ++i)
    	{
    		scanf("%d%d", &u, &v);
    		Add_Query(u, v, i);
    	}
    	a[1].dep = 1;
    	DFS1(1);
    	DSU(1, 0);
    	for (int i = 1; i <= m; ++i)
    	{
    		printf(ans[i] ? "Yes
    " : "No
    ");
    	}
    	return 0;
    }
    
    void Add_Edge(int u, int v, int idx)
    {
    	e[idx].to = v;
    	e[idx].next = h[u];
    	h[u] = idx;
    }
    
    void Add_Query(int u, int v, int idx)
    {
    	q[idx].to = v;
    	q[idx].next = hq[u];
    	hq[u] = idx;
    }
    
    void DFS1(int u)
    {
    	a[u].size = 1;
    	int v;
    	for (int i = h[u]; i; i = e[i].next)
    	{
    		v = e[i].to;
    		a[v].dep = a[u].dep + 1; 
    		DFS1(v);
    		a[u].size += a[v].size;
    		if (a[v].size > a[a[u].son].size) a[u].son = v; 
    	}
    }
    
    void DFS2(int u)
    {
    	vis[a[u].dep] ^= a[u].val;
    	for (int i = h[u]; i; i = e[i].next)
    	{
    		DFS2(e[i].to);
    	}
    }
    
    void DSU(int u, bool is)
    {
    	int v;
    	for (int i = h[u]; i; i = e[i].next)
    	{
    		v = e[i].to;
    		if (v == a[u].son) continue;
    		DSU(v, 1);
    	}
    	v = a[u].son;
    	if (v) DSU(v, 0);
    	vis[a[u].dep] ^= a[u].val;
    	for (int i = h[u]; i; i = e[i].next)
    	{
    		v = e[i].to;
    		if (v == a[u].son) continue;
    		DFS2(v); 
    	}
    	for (int i = hq[u]; i; i = q[i].next)
    	{
    		v = q[i].to;
    		if (!(vis[v] - lowbit(vis[v]))) ans[i] = 1;
    	}
    	if (is)
    	{
    		vis[a[u].dep] ^= a[u].val;
    		for (int i = h[u]; i; i = e[i].next)
    		{
    			v = e[i].to;
    			DFS2(v); 
    		}
    	}
    }
    

    当然,此题也可以用 DFS 序做,具体可以看这里

  • 相关阅读:
    总结面试常见题
    关于面试
    关于SQL经典题
    阶乘
    异常处理——捕获并抛出
    异常处理——异常越界
    异常处理——创建抛出
    输出异常
    抛出异常
    异常处理
  • 原文地址:https://www.cnblogs.com/kcn999/p/13402268.html
Copyright © 2011-2022 走看看