【题目记录】——2021牛客暑期多校训练营9

本文介绍了两道算法题目,一道涉及树的结构和传播,另一道涉及数字序列的定义。第一题中,树的节点权值具有特定规则,需要求解在一定条件下的最大传播范围。通过构建树状结构并进行深度优先搜索来解决。第二题则关注特定定义下的数字序列,通过将数字转换为三进制并进行调整来找到序列中的特定位置。这两题都展示了递归和树结构在算法问题中的应用。
摘要由CSDN通过智能技术生成


题目集地址 2021牛客暑期多校训练营9

E Eyjafjalla

题目地址E Eyjafjalla
参考博客2021牛客暑期多校训练营9 Eyjafjalla
题意:给出一棵树,每个树上都有权值,且保证父节点的权值比其所有子节点大。现在给出 m组询问,每次询问给出 u , l , r,表示u点只有在其权值为 [ l , r ]时才会被感染,除了 u 点其它点当且仅当其有一直连点被感染且自身权值在 [l,r] 时才会被感染,问最多能扩散到几个点。
思路:这个是关于树的题目,看样子难度不是很大,但是树这方面的内容不是我主要学习的方面,先把题目记录在这里。

#include <bits/stdc++.h>
typedef long long ll;
const int MAXN = 3e5 + 10, INF = 0x3f3f3f3f;
std::vector < int > G[MAXN], alls;
int n, m, t[MAXN], fa[MAXN][32], dist[MAXN], vis[MAXN], sz[MAXN];
int que[MAXN], l, r, root[MAXN], id[MAXN];
int cnt;
struct node
{
    int lson, rson, val;
}tr[MAXN * 40];
struct Query
{
    int root, l, r;
}Q[MAXN];
int idx = 0;
int getidx(int x)
{
    return std::lower_bound(alls.begin(), alls.end(), x) - alls.begin() + 1;
}
int build(int l, int r)
{
    if (l == r) return ++idx;
    int p = ++idx, mid = l + r >> 1;
    tr[p].lson = build(l, mid); tr[p].rson = build(mid + 1, r);
    return p;
}
int insert(int now, int prv, int l, int r)
{
    int pidx = ++idx;
    tr[pidx].val = tr[prv].val + 1;
    if (l == r) return pidx;
    int mid = l + r >> 1;
    if (now <= mid) tr[pidx].lson = insert(now, tr[prv].lson, l, mid), tr[pidx].rson = tr[prv].rson;
    else tr[pidx].lson = tr[prv].lson, tr[pidx].rson = insert(now, tr[prv].rson, mid + 1, r);
    return pidx;
}
int query(int p, int q, int t, int s, int l, int r)
{
    if (l <= t && s <= r) return tr[q].val - tr[p].val;
    int mid = t + s >> 1, ans = 0;
    if (l <= mid) ans += query(tr[p].lson, tr[q].lson, t, mid, l, r);
    if (r > mid) ans += query(tr[p].rson, tr[q].rson, mid + 1, s, l, r);
    return ans;
}
void dfs(int now, int f)
{
    sz[now] = 1; ++cnt;
    root[cnt] = insert(getidx(t[now]), root[cnt - 1], 1, m);
    id[now] = cnt;
    for (auto &i : G[now])
    {
        if (i == f) continue;
        dfs(i, now);
        sz[now] += sz[i];
    }
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n - 1; ++i)
    {
        int u, v; scanf("%d%d", &u, &v);
        G[u].push_back(v); G[v].push_back(u);
    }
    t[0] = INF;
    for (int i = 1; i <= n; ++i)
        scanf("%d", &t[i]), alls.push_back(t[i]);
    int q; scanf("%d", &q);
    for (int i = 1; i <= q; ++i)
    {
        scanf("%d%d%d", &Q[i].root, &Q[i].l, &Q[i].r);
        alls.push_back(Q[i].l); alls.push_back(Q[i].r);
    }
    std::sort(alls.begin(), alls.end());
    alls.erase(std::unique(alls.begin(), alls.end()), alls.end());
    m = alls.size();
    dist[1] = 1, vis[1] = 1;
    que[1] = 1, l = r = 1;
    while (l <= r)
    {
        int u = que[l++];
        for (auto &i : G[u])
            if (!vis[i])
            {
                dist[i] = dist[u] + 1, fa[i][0] = u;
                que[++r] = i, vis[i] = 1;
                for (int j = 1; j <= 31; ++j)
                    fa[i][j] = fa[fa[i][j - 1]][j - 1];
            }
    }
    root[0] = build(1, m); dfs(1, -1);
    for (int i = 1; i <= q; ++i)
    {
        int rx = Q[i].root;
        if (t[rx] > Q[i].r || t[rx] < Q[i].l)
        {
            printf("0\n");
            continue;
        }
        for (int j = 31; j >= 0; --j)
            if (t[fa[rx][j]] <= Q[i].r) rx = fa[rx][j];
        printf("%d\n", query(root[id[rx] - 1], root[id[rx] + sz[rx] - 1], 1, m, getidx(Q[i].l), getidx(Q[i].r)));
    }
    return 0;
}

H Happy Number

题目地址H Happy Number
题意:定义数字2,6,3的数字为ha

ppy number,问第n个happy number是哪个数字。
思路:比较简单,找到排数的规律就行了。但这个三进制的数值表示是1到3。把n转换为三进制之后对于每个小于等于0的位向高位借一个3即可。

/*
**Author:skj
**Time:
**Function:
*/
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int a[100];
int cnt;
int main()
{
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
    int n;
    scanf("%d",&n);
    while(n)
    {
        a[cnt++]=(n%3);
        n/=3;
    }
    for(int i = 0;i < cnt - 1;i++)//最高位不做借位处理
    {
        if(a[i] <= 0)
        {
            a[i]+=3;
            a[i+1]--;
        }
    }
    for(int i = cnt-1;i >= 0;i--)
    {
        if(a[i] == 1)
        {
            printf("2");
        }
        if(a[i] == 2)
        {
            printf("3");
        }
        if(a[i] == 3)
        {
            printf("6");
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值