zoukankan      html  css  js  c++  java
  • P2023 [AHOI2009] 维护序列(线段树水题)

    题目描述

    老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。

    输入输出格式

    输入格式:

    第一行两个整数N和P(1≤P≤1000000000)。第二行含有N个非负整数,从左到右依次为a1,a2,…,aN, (0≤ai≤1000000000,1≤i≤N)。第三行有一个整数M,表示操作总数。从第四行开始每行描述一个操作,输入的操作有以下三种形式: 操作1:“1 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai×c (1≤t≤g≤N,0≤c≤1000000000)。 操作2:“2 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai+c (1≤t≤g≤N,0≤c≤1000000000)。 操作3:“3 t g”(不含双引号)。询问所有满足t≤i≤g的ai的和模P的值 (1≤t≤g≤N)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

    输出格式:

    对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。

    输入输出样例

    输入样例#1: 复制
    1. 7 43
    2. 1 2 3 4 5 6 7
    3. 5
    4. 1 2 5 5
    5. 3 2 4
    6. 2 3 7 9
    7. 3 1 3
    8. 3 4 7
    输出样例#1: 复制
    1. 2
    2. 35
    3. 8

    说明

    【样例说明】

    初始时数列为(1,2,3,4,5,6,7)。

    经过第1次操作后,数列为(1,10,15,20,25,6,7)。

    对第2次操作,和为10+15+20=45,模43的结果是2。

    经过第3次操作后,数列为(1,10,24,29,34,15,16}

    对第4次操作,和为1+10+24=35,模43的结果是35。

    对第5次操作,和为29+34+15+16=94,模43的结果是8。

    测试数据规模如下表所示

    数据编号 1 2 3 4 5 6 7 8 9 10

    N= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000

    M= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000

    Source: Ahoi 2009

    题解:很水的线段树水题= =但是卡了半小时的60分,重写了两遍线段树也没找到……后来发现有一些小地方没模p(吐了),总之能模就模,往死里模

    具体见代码;

    #define _CRT_SECURE_NO_DepRECATE
    #define _CRT_SECURE_NO_WARNINGS
    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <iomanip>
    #include <string>
    #include <algorithm>
    #include <bitset>
    #include <cstdlib>
    #include <cctype>
    #include <iterator>
    #include <vector>
    #include <cstring>
    #include <cassert>
    #include <map>
    #include <queue>
    #include <set>
    #include <stack>
    #include <stdio.h>
    #define ll long long
    #define INF 0x3f3f3f3f
    #define ld long double
    const ld pi = acos(-1.0L), eps = 1e-8;
    ll qx[4] = { 0,0,1,-1 }, qy[4] = { 1,-1,0,0 }, qxx[2] = { 1,-1 }, qyy[2] = { 1,-1 };
    using namespace std;
    struct node
    {
        ll l, r, sum, lz = 0, mlz = 1;
    }tree[1000000];
    ll input[1000000], p = 1;
    inline void pushdown(ll i)
    {
        ll k1 = tree[i].mlz, k2 = tree[i].lz;
        tree[i << 1].sum = (tree[i << 1].sum * k1 + k2 * (tree[i << 1].r - tree[i << 1].l + 1)) % p;
        tree[i << 1 | 1].sum = (tree[i << 1 | 1].sum * k1 + k2 * (tree[i << 1 | 1].r - tree[i << 1 | 1].l + 1)) % p;
        tree[i << 1].mlz = (tree[i << 1].mlz * k1) % p;
        tree[i << 1 | 1].mlz = (tree[i << 1 | 1].mlz * k1) % p;
        tree[i << 1].lz = (tree[i << 1].lz * k1 + k2) % p;
        tree[i << 1 | 1].lz = (tree[i << 1 | 1].lz * k1 + k2) % p;
        tree[i].lz = 0;
        tree[i].mlz = 1;
    }
    inline void build(ll i, ll l, ll r)//构建二叉树
    {
        tree[i].l = l;
        tree[i].r = r;
        if (l == r)//如果为叶子结点
        {
            tree[i].sum = input[l] % p;
            return;
        }
        ll mid = (l + r) >> 1;//i*2为左儿子编号,i*2+1为右儿子编号
        build(i * 2, l, mid);//构造左子树
        build(i * 2 + 1, mid + 1, r);//构造右子树
        tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % p;
        return;
    }
    inline ll search(ll i, ll l, ll r)
    {
        if (tree[i].l >= l && tree[i].r <= r)//如果该区间被完全包含在目标区间里面
        {
            return tree[i].sum % p;
        }
        if (tree[i].r< l || tree[i].l > r)//如果该区间和目标区间没关系
        {
            return 0;
        }
        pushdown(i);
        ll s = 0;
        if (tree[i * 2].r >= l)//如果左儿子和目标区间有交集
        {
            s += search(i * 2, l, r) % p;
        }
        if (tree[i * 2 + 1].l <= r)//如果右儿子和目标区间有交集
        {
            s += search(i * 2 + 1, l, r) % p;
        }
        return s % p;
    }
    inline void add(ll i, ll l, ll r, ll k)
    {
        if (tree[i].l > r || tree[i].r < l)
        {
            return;
        }
        if (tree[i].l >= l && tree[i].r <= r)
        {
            tree[i].sum += k * (tree[i].r - tree[i].l + 1);
            tree[i].sum %= p;
            tree[i].lz += k;
            tree[i].lz %= p;
            return;
        }
        pushdown(i);
        if (l <= tree[i * 2].r)
        {
            add(i * 2, l, r, k);
        }
        if (r >= tree[i * 2 + 1].l)
        {
            add(i * 2 + 1, l, r, k);
        }
        tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % p;//返回的时候更新
        return;
    }
    inline void multi(ll i, ll l, ll r, ll k)
    {
        if (tree[i].l > r || tree[i].r < l)
        {
            return;
        }
        if (tree[i].l >= l && tree[i].r <= r)
        {
            tree[i].sum *= k;
            tree[i].sum %= p;
            tree[i].mlz *= k;
            tree[i].mlz %= p;
            tree[i].lz = (tree[i].lz * k) % p;
            return;
        }
        pushdown(i);
        if (l <= tree[i << 1].r)
        {
            multi(i << 1, l, r, k);
        }
        if (r >= tree[i << 1 | 1].l)
        {
            multi(i << 1 | 1, l, r, k);
        }
        tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % p;
        return;
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        ll n, t;
        cin >> n >> t;
        p = t;
        for (ll i = 1; i <= n; i++)
        {
            cin >> input[i];
        }
        build(1, 1, n);
        ll x, y, a, b, c;
        cin >> x;
        for (ll i = 0; i < x; i++)
        {
            cin >> y;
            if (y == 1)
            {
                cin >> a >> b >> c;
                multi(1, a, b, c);
                
            }
            else if (y == 2)
            {
                cin >> a >> b >> c;
                add(1, a, b, c);
            }
            else if (y == 3)
            {
                cin >> a >> b;
                cout << ::search(1, a, b) % p << endl;
            }
        }
        return 0;
    }
  • 相关阅读:
    ElasticSearch搜索引擎安装配置拼音插件pinyin
    ElasticSearch搜索引擎安装配置中文分词器IK插件
    Linux系统中ElasticSearch搜索引擎安装配置Head插件
    阿里云服务器Linux系统安装配置ElasticSearch搜索引擎
    盒子模型
    div与span的区别
    .与localhost与 .sqlexpress的区别
    C#-多态
    C#-里氏转换
    C#-继承
  • 原文地址:https://www.cnblogs.com/Load-Star/p/12695202.html
Copyright © 2011-2022 走看看