数据结构难题

一 问题描述

有 N 个数,a1,a2,an,每次都可以将[l,r]区间的每个数字都更改为数字 x,或将[l,r]区间每个大于 x 的 ai 都更改为最大公约数 gcd(ai,x),请输出最后的序列。

二 输入和输出

1 输入

第 1 行包含一个整数T,表示测试用例的数量。每个测试用例的第 1 行都包含整数 n,下一行包含以空格分隔的 n 个整数 a1,a2,an,再下一行包含一个整数 Q,表示操作数量。下面的 Q 行,每行都包含四个整数 t、l、 r、 x,t 表示操作类型,l,r 表示出现左右端点。

2 输出

对每个测试用例,都单行输出以空格分隔的最终序列。

三 输入和输出样例

1 输入样例

1

10

16807 282475249 1622650073 984943658 1144108930 470211272 101027544 1457850878 1458777923 2007237709

10

1 3 6 74243042

2 4 8 16531729

1 3 4 1474833169

2 1 8 1131570933

2 7 9 1505795335

2 3 7 101929267

1 4 10 1624379149

2 2 8 2110010672

2 6 7 156091745

1 2 5 937186357

2 输出样例

16807 937186357 937186357 937186357 937186357 1 1 1624379149 1624379149 1624379149

四 分析和设计

1 分析

本问题很明显是区间更新问题,但不仅仅是简单的区间更新,而是将 [l,r] 区间的每个大于 x 的 ai 都更改为 gcd(ai,x)。

2 设计

a 创建线段数

b 区间更新,将 [l,r] 区间的每个数字都更改为数字 x

c 区间更新,将 [l,r] 区间的每个大于 x 的 ai 都更改为 gcd(ai,x)。

五 代码

package com.platform.modules.alg.alglib.hdu4902;

public class Hdu4902 {
    private int N = 100005;
    private int a[] = new int[N];
    private int maxs[] = new int[N << 2];
    private int lazy[] = new int[N << 2];
    private int n;
    private int m;

    public String output = "";

    // 最大公约数
    int gcd(int a, int b) {
        if (b == 0) return a;
        else return gcd(b, a % b);
    }

    // 上传
    void PushUp(int i) {
        maxs[i] = Math.max(maxs[i << 1], maxs[i << 1 | 1]);
    }

    // 下传
    void PushDown(int i) {
        if (lazy[i] != 0) {
            lazy[i << 1] = lazy[i << 1 | 1] = lazy[i];
            maxs[i << 1] = maxs[i << 1 | 1] = maxs[i];
            lazy[i] = 0;
        }
    }

    // 建线段树
    void build(int l, int r, int i) {
        if (l == r) {
            lazy[i] = a[l];
            maxs[i] = lazy[i];
            return;
        }
        int mid = (l + r) >> 1;
        build(l, mid, i << 1);
        build(mid + 1, r, i << 1 | 1);
        PushUp(i);
    }

    // 类型1更新
    void update1(int x, int L, int R, int l, int r, int i) {
        if (L <= l && r <= R) {
            lazy[i] = maxs[i] = x;
            return;
        }
        PushDown(i);
        int mid = (l + r) >> 1;
        if (L <= mid)
            update1(x, L, R, l, mid, i << 1);
        if (R > mid)
            update1(x, L, R, mid + 1, r, i << 1 | 1);
        PushUp(i);
    }

    // 类型2更新
    void update2(int x, int L, int R, int l, int r, int i) {
        if (maxs[i] <= x) return;
        if (lazy[i] != 0 && L <= l && r <= R) {
            lazy[i] = gcd(lazy[i], x);
            maxs[i] = lazy[i];
            return;
        }
        PushDown(i);
        int mid = (l + r) >> 1;
        if (L <= mid)
            update2(x, L, R, l, mid, i << 1);
        if (R > mid)
            update2(x, L, R, mid + 1, r, i << 1 | 1);
        PushUp(i);
    }

    void print(int l, int r, int i) {
        if (l == r) {
            output += lazy[i] + " ";
            return;
        }
        PushDown(i);
        int mid = (l + r) >> 1;
        print(l, mid, i << 1);
        print(mid + 1, r, i << 1 | 1);
    }

    public String cal(String input) {
        int l, r, opt;
        int x;
        String[] line = input.split("\n");
        n = Integer.parseInt(line[0]);
        String[] nums = line[1].split(" ");
        for (int i = 1; i <= n; i++)
            a[i] = Integer.parseInt(nums[i - 1]);
        build(1, n, 1);
        m = Integer.parseInt(line[2]);
        int j = 0;
        while (m-- > 0) {
            String[] command = line[3 + j].split(" ");
            j++;
            opt = Integer.parseInt(command[0]);
            l = Integer.parseInt(command[1]);
            r = Integer.parseInt(command[2]);
            x = Integer.parseInt(command[3]);
            if (opt == 1) update1(x, l, r, 1, n, 1);
            else update2(x, l, r, 1, n, 1);
        }
        print(1, n, 1);
        return output;
    }
}

六 测试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值