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

来源:互联网 发布:servo guide软件下载 编辑:程序博客网 时间:2024/06/05 08:14

链接

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|1lint 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;}
0 0
原创粉丝点击