HDU 5593 ZYB's Tree

13 篇文章 0 订阅
题意:

给定一棵树,对每个点 i ,统计树上面与其距离不超过 k 的点的个数,然后所有值求异或。 1N500000 , 1K10

思路:

暴力,开始想到了同样的思路,觉得暴力会挂的样子,没敢去写。。。

首先处理出 dp[i][j] 表示 i 节点子树中与 i 的距离 j 的点的数目。

对于每个节点统计答案,往上枚举距离在 k <script type="math/tex" id="MathJax-Element-512">k</script> 内的LCA,然后去统计另外一个满足条件的节点的数目,注意边界条件的处理,还有去重哦!!!

代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <bitset>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define INF 0x3f3f3f3f
#define eps 1e-8
#define FI first
#define SE second
#define maxm 1000009
#define maxn 500009
using namespace std;
struct Edge{
    int v,next;
}edge[maxm];
int head[maxn],tot,n,m,A,B;
int dp1[maxn][11],fa[maxn];
void init(){
    memset(head,-1,sizeof(head));
    tot = 0;
}
inline void addedge(int u,int v){
    edge[tot].v = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void dfs(int u){
    for(int i = 0;i <= m;i ++)
        dp1[u][i]=0;
    dp1[u][0] = 1;
    int v;
    for(int e = head[u];e != -1;e = edge[e].next){
        v = edge[e].v;
        fa[v] = u;
        dfs(v);
        for(int i = 0;i < m;i ++)
            dp1[u][i+1] += dp1[v][i];
    }
}
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt --){
        init();
        scanf("%d%d%d%d",&n,&m,&A,&B);
        for(int i = 2;i <= n;i ++){
            int fa = (1LL*A*i+B)%(i-1)+1;
            addedge(fa,i);
        }
        fa[1] = -1;
        int ans = 0;
        dfs(1);//得到i为子树里,距离为j的点的个数
        for(int i = 1;i <= n;i ++)
            for(int j = 1;j <= m;j ++)
                dp1[i][j] += dp1[i][j-1];//得到i为子树里,距离<=j的点的个数

        for(int i = 1;i <= n;i ++){
            int val = dp1[i][m];//首先统计i子树中满足条件的点
            int cnt = 1,cur = i;
            //枚举LCA
            while(cnt <= m && fa[cur] != -1){
                val += dp1[fa[cur]][m-cnt];
                if(m-cnt-1 >= 0)
                    val -= dp1[cur][m-cnt-1];//减去重复统计的
                cnt ++;
                cur = fa[cur];
            }
            ans = ans^val;    
        }
        printf("%d\n",ans);
    }
    //system("pause");
    return 0;
}   
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,这是一道关于二叉树的问题,需要输出每个二叉树的层序遍历。如果二叉树没有完全给出,则输出“not complete”。而且,这道题目是一个ACM竞赛的题目,需要使用Java语言进行编写。 以下是Java语言的代码实现: ```java import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { String s = sc.nextLine(); if (s.equals("")) { continue; } String[] arr = s.split(" "); int len = arr.length; int[] tree = new int[len]; boolean[] flag = new boolean[len]; for (int i = 0; i < len; i++) { if (arr[i].equals("()")) { tree[i] = -1; flag[i] = true; } else { tree[i] = Integer.parseInt(arr[i].substring(1, arr[i].length() - 1)); } } int root = 0; for (int i = 0; i < len; i++) { if (!flag[i]) { root = i; break; } } boolean isComplete = true; Queue<Integer> queue = new LinkedList<>(); queue.offer(root); int index = 1; while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { int cur = queue.poll(); if (tree[cur] == -1) { if (index < len && !flag[index]) { isComplete = false; } } else { if (cur * 2 + 1 < len) { queue.offer(cur * 2 + 1); if (tree[cur * 2 + 1] != -1) { flag[cur * 2 + 1] = true; } } if (cur * 2 + 2 < len) { queue.offer(cur * 2 + 2); if (tree[cur * 2 + 2] != -1) { flag[cur * 2 + 2] = true; } } } index++; } } if (!isComplete) { System.out.println("not complete"); continue; } queue.offer(root); StringBuilder sb = new StringBuilder(); while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { int cur = queue.poll(); sb.append(tree[cur]).append(" "); if (cur * 2 + 1 < len && tree[cur * 2 + 1] != -1) { queue.offer(cur * 2 + 1); } if (cur * 2 + 2 < len && tree[cur * 2 + 2] != -1) { queue.offer(cur * 2 + 2); } } } System.out.println(sb.toString().trim()); } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值