[HDU 5475] An easy problem (线段树)

本文介绍了一个涉及模运算撤销的问题及解决思路。通过构建线段树,实现对一系列模运算的高效撤销操作。针对两种询问类型,一是更新并输出模运算结果,二是撤销指定位置的乘法操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接

An easy problem


题意

T组样例。
整数X起初为1,给出Q个询问和一个整数M,对每个询问,如果是(1, n),则将X更新为其乘n余M的结果并输出,如果是(2, n),则将第n个询问中的乘数从X中除去,更新并输出结果。


思路

主要问题在于第2种操作。
由于整个过程是不停在取模的,所以不能将X直接除以第n个询问的乘数因子。我们对操作建立线段树,则对询问(2, n),我们只要将第n个操作的因子变为1,再合并得到新的总因子,就能把那个乘数撤销掉了。
能这么做的关键在于乘法、取模运算是“叠加”的,在线段树区间进行合并的时候,直接把两个子区间的乘数因子乘起来取模就好。如果存在多种运算,并且运算之间的关系不容易叠加,就不能利用线段树区间合并的优势进行维护了。


代码
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long lint;
#define maxn (100010)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
lint seg[maxn << 2], mod;
void build(int l, int r, int rt)
{
    seg[rt] = 1;
    if(l == r) return ;
    int m = (l + r) >> 1;
    build(lson), build(rson);
}
void update(int i, int a, int l, int r, int rt)
{
    if(l == r) { seg[rt] = a % mod; return; }
    int m = (l + r) >> 1;
    if(i <= m) update(i, a, lson);
    else update(i, a, rson);
    seg[rt] = (seg[rt<<1] * seg[rt<<1|1]) % mod;
}
lint query(int L, int R, int l, int r, int rt)
{
    if(L <= l && r <= R) { return seg[rt]; }
    int m = (l + r) >> 1, ret = 1;
    if(L <= m) ret = ret * query(L, R, lson) % mod;
    if(R > m) ret = ret * query(L, R, rson) % mod;
    return ret;
}
int main()
{
    //freopen("5475.txt", "r", stdin);

    int T, kase = 0;
    cin >> T;
    while(T--)
    {

        printf("Case #%d:\n", ++kase);

        int Q, M;
        cin >> Q >> M;
        mod = M;
        build(1, Q, 1);
        for(int i = 1, op, x; i <= Q; i++)
        {
            scanf("%d%d", &op, &x);
            if(op == 1) update(i, x, 1, Q, 1);
            else update(x, 1, 1, Q, 1);
            printf("%I64d\n", query(1, i, 1, Q, 1));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值