羅区の問題解決[P4588] [TJOI2018]数学

タイトル説明

小豆の数があります\(X \) 初期値の\(1 \) と小豆\(Q \)の操作は、操作の2つの種類があります。

\(1 \; Mの\):\ (X = X \タイムズM \)出力\(X \%MOD \)

\(2 \; POS \):\ (X = X / \)\(POS \)操作の回数は、(保証乗算\(POS \)特定の型に操作を\(1 \)それぞれについて、タイプ\(1 \)動作がアップつの他の)出力することで\(X \%MOD \)

入力形式

合計\(T \)入力のセット(\(T \ leq5 \) )。

入力のセットごとに、最初の行が二桁である\(Q、MOD \) \(Q \ leq100000、MOD \ leq100000000 \) )。

\(Q \)行、各アクト操作型\(OP \) 操作または番号乗算(Mの\)\(すべての入力が有効であることを保証するために)。

出力フォーマット

操作実行を含む各操作、出力線用\(X \%MOD \)

サンプル入力と出力

入力#1

1
10 1000000000
1 2
2 1
1 2
1 10
2 3
2 4
1 6
1 7
1 12
2 7

出力#1

2
1
2
20
10
1
6
42
504
84

説明/ヒント

以下のための\(20 \%の\)データ、\(1 \のLeq Q \ leq500 \)

以下のための\(100 \%の\)データ、\(1 \のLeq Q \ leq100000 \)

問題の解決策

この質問は思考では困難であり、どのように困難なツリーラインだと思います。

暴力シミュレーションが思うのは簡単です、しかし、この質問では、暴力シミュレーションは間違っています!

一連の\(\ texttt {ハック} \ ) のデータ:

1
2 10
1 99
2 99

出力は次のようになります。

9
1

......あなたができるように精密に見えますが、空間的な複雑さに触れ~~

ここで直接正ソリューションの話します。

製品部セグメントツリーとメンテナンス操作、場合\(1 \)現在のノード操作の値が変更される(Mの\)を\ \ (2 \)加え回数が配置するノードの値代わりに\(1 \)

出力値は、出力ライン......ルートノードに指示することができます。

コード

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define int long long//注意long long
#define itn int
#define gI gi

using namespace std;

inline int gi()//快读
{
    int f = 1, x = 0; char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
    while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return f * x;
}

int t, q, mod, tr[400003], ans;

inline int ls(int p) {return p << 1;}//左儿子
inline int rs(itn p) {return p << 1 | 1;}//右儿子

void modify(int ql, int qr, int z, int l, int r, int p)//修改节点
{
    if (l == r && l == ql) {tr[p] = z; return;}//到了叶子节点进行修改
    int mid = (l + r) >> 1;
    if (ql <= mid) modify(ql, qr, z, l, mid, ls(p));//递归左子树
    if (qr > mid) modify(ql, qr, z, mid + 1, r, rs(p));//递归右子树
    tr[p] = (tr[ls(p)] % mod * tr[rs(p)] % mod) % mod;//上传节点
    return;
}

signed main()
{
    t = gi();
    while (t--)
    {
        q = gi(), mod = gi();
        for (int i = 1; i <= 400001; i+=1) tr[i] = 1;//注意,本题中不需要建树,只需要把所有节点的值设为1
        for (int i = 1; i <= q; i+=1)
        {
            int op = gi(), m = gi();
            if (op == 1) modify(i, i, m, 1, q, 1);//操作1,将第i个点的值修改为m
            else modify(m, m, 1, 1, q, 1);//操作2,将第m个点的值修改为1
            printf("%lld\n", tr[1]);//输出
        }
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/xsl19/p/11617062.html