蓝桥 冰山 高精度 模拟 splay伸展树 java

🍑 算法题解专栏


🍑 蓝桥 冰山

在这里插入图片描述
输入

1 3 6
1
6 1
2 2
-1 1

输出

8
16
11

在这里插入图片描述


👨‍🏫 大佬题解 (AC)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
const long long MOD = 998244353;

int n, m;
long long K;
struct Node {
    int s[2], p;    // s[0] 左儿子 s[1] 右儿子 p 父节点
    long long v,    // 冰山体积
              num,  // 冰山个数
              cnt,  // 子树包含冰山个数
              sum,  // 子树包含冰山体积之和
              flag; // 懒惰标记

    Node() {};
    Node(long long _v, int _p) {v = _v; p = _p; s[0] = s[1] = 0; num = cnt = sum = flag = 0;}
} tr[maxn];
int root, idx;

void add(long long &a, long long b) {
    a = (a + b % MOD) % MOD;
}

void push_up(int x) {
    tr[x].cnt = tr[x].num + tr[tr[x].s[0]].cnt + tr[tr[x].s[1]].cnt;
    tr[x].cnt %= MOD;
    tr[x].sum = tr[x].num * tr[x].v + tr[tr[x].s[0]].sum + tr[tr[x].s[1]].sum;
    tr[x].sum %= MOD;
    tr[x].sum = (tr[x].sum + MOD) % MOD;
}

void t_flag(int x, long long tmp) {
    if (x) {
        tr[x].flag += tmp;
        tr[x].v += tmp;
        add(tr[x].sum, tr[x].cnt * tmp);
    }
}

void push_down(int x) {
    if (tr[x].flag) {
        t_flag(tr[x].s[0], tr[x].flag);
        t_flag(tr[x].s[1], tr[x].flag);
        tr[x].flag = 0;
    }
}

void f_s(int p, int u, bool k) {
    if (p) tr[p].s[k] = u;
    tr[u].p = p;
}

void rot(int x) {
    int y = tr[x].p, z = tr[y].p;
    bool k = tr[y].s[1] == x;
    f_s(z, x, tr[z].s[1]==y);
    f_s(y, tr[x].s[k^1], k);
    f_s(x, y, k^1);
    push_up(y), push_up(x);
}

void splay(int x, int k) {
    while (tr[x].p != k) {
        int y = tr[x].p, z = tr[y].p;
        if (z != k)
            (tr[y].s[1]==x) ^ (tr[z].s[1]==y) ? rot(x) : rot(y);
        rot(x);
    }
    if (!k) root = x;
}

void ins(long long v, long long num) {
    int u = root, p = 0;
    while (u && tr[u].v != v) {
        push_down(u);
        p = u, u = tr[u].s[v > tr[u].v];
    }
    if (!u) {
        tr[u = ++idx] = Node(v, p);
        if (p) tr[p].s[v > tr[p].v] = u;
    }
    else
        push_down(u);   // 如果不是新建的节点,需要push_down一下
    add(tr[u].num, num);
    add(tr[u].cnt, num);
    add(tr[u].sum, num * v);
    splay(u, 0);
}

bool check(int u) {
    return tr[u].v > 0 && tr[u].v <= K;
}

void get1() {
    int u = root, p = 0, x = 0;
    while (u) {
        push_down(u);
        p = u;
        if (tr[u].v > 0) {
            x = u;
            u = tr[u].s[0];
        }
        else u = tr[u].s[1];
    }
    if (x) {
        splay(x, 0);
        tr[x].s[0] = 0;
        push_up(x);
    }
    else tr[root = 0] = Node(0, 0);
}

void get2() {
    int u = root, p = 0, x = 0;
    while (u) {
        push_down(u);
        p = u;
        if (tr[u].v <= K) {
            x = u;
            u = tr[u].s[1];
        }
        else u = tr[u].s[0];
    }
    int y;
    if (x) splay(x, 0), y = tr[x].s[1];
    else y = root;
    if (y) {
        long long cnt = tr[y].cnt, sum = tr[y].sum;
        if (y != root) tr[x].s[1] = 0;
        else tr[root = 0] = Node(0, 0);
        push_up(root);
        ins(K, cnt);
        ins(1, (sum - cnt * K % MOD + MOD) % MOD);
    }
}

int main() {
    scanf("%d%d%lld", &n, &m, &K);
    for (int i = 0; i < n; i++) {
        int v;
        scanf("%d", &v);
        ins(v, 1);
    }
    while (m--) {
        int x, y;
        scanf("%d%d", &x, &y);
        t_flag(root, x);
        ins(y, 1);
        get1();
        get2();
        printf("%lld\n", tr[root].sum);
    }
    return 0;
}

🍑 BigInteger(70%)

import java.math.BigInteger;
import java.util.*;

public class Main
{
	static HashMap<Long, BigInteger> map = new HashMap<>();
	static BigInteger zero = BigInteger.ZERO;
	static BigInteger one = BigInteger.ONE;
	static BigInteger mod = new BigInteger("998244353");

	public static void main(String[] args)
	{
		Scanner sc = new Scanner(System.in);
		long n = sc.nextLong();
		long m = sc.nextLong();// 观察的天数
		long k = sc.nextLong();// 大小限制
		for (int i = 0; i < n; i++)
		{
			long t = sc.nextLong();
			map.put(t, map.getOrDefault(t, zero).add(one));
		}

		while (m-- > 0)
		{
			long x = sc.nextLong();
			long y = sc.nextLong();
			HashMap<Long, BigInteger> tmp = new HashMap<>();
			BigInteger sum = zero;
			if (y != 0)
			{
				sum = sum.add(new BigInteger(y + ""));
				tmp.put(y, one);
			}
			for (Long v : map.keySet())
			{
//				v:冰山的体积,cnt:冰山的数量
				BigInteger cnt = map.get(v);
				long vv = v + x;
				if (vv <= 0)// 冰山消失
					continue;
				sum = sum.add(cnt.multiply(new BigInteger(vv + "")));// 计算总和
				sum = sum.divideAndRemainder(mod)[1];
//				处理新冰山
				if (vv <= k)// 没超限,原冰山加上体积 = 新冰山
				{
					tmp.put(vv, tmp.getOrDefault(vv, zero).add(cnt));
				} else // 超限:分解出新的小冰山
				{
					tmp.put(k, tmp.getOrDefault(k, zero).add(cnt));// 主体冰山,体积为 k,数量为 cnt

					BigInteger cnt1 = cnt.multiply(new BigInteger((vv - k) + ""));// 体积为1的冰山数量
					tmp.put(1l, tmp.getOrDefault(1l, zero).add(cnt1));
				}
			}
			System.out.println(sum.toString());
			map = tmp;
		}
	}
}

🍑 long (60%)

注意:1 和 1l 的哈希值不一样
冰山数量会爆long,使用上边BigInteger的代码,与Long.MaxValue比较一下可知

import java.io.*;
import java.util.*;

public class Main
{
    static int mod = 998244353;
    static HashMap<Long, Long> map = new HashMap<>();
    static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));

    public static void main(String[] args) throws IOException
    {
//        Scanner sc = new Scanner(System.in);
//        long n = sc.nextLong();
//        long m = sc.nextLong();// 观察的天数
//        long k = sc.nextLong();// 大小限制
        String[] ss = in.readLine().split(" ");
        long n = Long.parseLong(ss[0]);
        long m = Long.parseLong(ss[1]);
        long k = Long.parseLong(ss[2]);

        ss = in.readLine().split(" ");
        for (int i = 0; i < n; i++)
        {
//            Long t = sc.nextLong();
            long t = Long.parseLong(ss[i]);
            map.put(t, (map.getOrDefault(t, 0l) + 1) % mod);
        }

        while (m-- > 0)
        {
//            long x = sc.nextLong();// 体积变换量
//            long y = sc.nextLong();// 新来的冰山体积
            ss = in.readLine().split(" ");
            long x = Long.parseLong(ss[0]);
            long y = Long.parseLong(ss[1]);

            HashMap<Long, Long> tmp = new HashMap<>();
            long sum = 0;
            if (y != 0)
            {
                tmp.put(y, 1l);// 先把y放进来
                sum = y;// 再把 y 的体积加上
            }
            for (long vol : map.keySet())// 枚举前一天的所有冰山
            {
                Long cnt = map.get(vol);// 获取当前冰山的个数
                if (cnt < 0)
                    System.out.println(vol + "  " + cnt + " bug");
                long vv = (vol + x) % mod;// 变化后的体积
                if (vv <= 0)// 冰山消失
                {
//                    map.remove(vol);//从记录中去除
                    continue;
                }
                sum = (sum + (vv * cnt) % mod) % mod;
                if (vv <= k)
                    tmp.put(vv, (tmp.getOrDefault(vv, 0l) + cnt) % mod);
                else
                {
                	// TMD 就是这里的 vv 卡了我半天
                	//tmp.put(k, (tmp.getOrDefault(vv, 0l) + cnt) % mod);
                    tmp.put(k, (tmp.getOrDefault(k, 0l) + cnt) % mod);
                    long t = vv - k;// 每座大冰山都能分解出 t 座体积为 1 的小冰山
                    t *= cnt;// 有 cnt 座大冰山
                    tmp.put(1l, (tmp.getOrDefault(1L, 0l) + t) % mod);
                }
            }

            map = tmp;
//            System.out.println(sum);
            out.write(sum + "\n");
        }
        out.flush();
    }
}
树上选点是蓝桥Java题目中的一种类型,通常需要在给定的树结构中选择一个或多个节点作为目标节点,并进行相应的操作。下面是一个简单的树上选点蓝桥Java题解的示例: 题目描述: 给定一棵有N个节点的树,每个节点上都有一个非负整数值。现在需要选择一些节点,使得选择的节点的值之和最大,且所选节点不能相邻(即选了一个节点,则其父节点和子节点都不能选)。请编写一个程序,计算出最大的节点值之和。 解题思路: 这是一个典型的动态规划问题。我们可以定义一个数组dp,其中dp[i]表示以第i个节点为根节点的子树中所选节点的最大值之和。对于每个节点i,有两种情况: 1. 选择节点i:则其子节点都不能选,所以dp[i] = val[i] + dp[grandchild1] + dp[grandchild2] + ... 2. 不选择节点i:则其子节点可以选择或不选择,所以dp[i] = max(dp[child1], dp[child2], ...) 根据以上思路,我们可以使用递归或者迭代的方式来计算dp数组。最终,所求的最大值即为dp,其中1表示根节点。 代码示例: ```java public class TreeSelectPoint { public static void main(String[] args) { int[] values = {0, 1, 2, 3, 4, 5}; // 节点值数组,下标从1开始 int[][] edges = {{1, 2}, {1, 3}, {2, 4}, {2, 5}}; // 树的边关系数组 int n = values.length - 1; // 节点个数 int[] dp = new int[n + 1]; // 动态规划数组 // 构建树的邻接表 List<List<Integer>> adjacencyList = new ArrayList<>(); for (int i = 0; i <= n; i++) { adjacencyList.add(new ArrayList<>()); } for (int[] edge : edges) { int u = edge[0]; int v = edge[1]; adjacencyList.get(u).add(v); adjacencyList.get(v).add(u); } dfs(1, -1, values, adjacencyList, dp); // 从根节点开始进行深度优先搜索 System.out.println(dp[1]); // 输出最大节点值之和 } private static void dfs(int cur, int parent, int[] values, List<List<Integer>> adjacencyList, int[] dp) { dp[cur] = values[cur]; // 初始化当前节点的dp值为节点值 for (int child : adjacencyList.get(cur)) { if (child != parent) { // 避免重复访问父节点 dfs(child, cur, values, adjacencyList, dp); dp[cur] += dp[child]; // 更新当前节点的dp值 } } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值