Codeforces 438D 线段树 解题报告

D. The Child and Sequence

At the children’s day, the child came to Picks’s house, and messed his house up. Picks was angry at him. A lot of important things were lost, in particular the favorite sequence of Picks.
Fortunately, Picks remembers how to repair the sequence. Initially he should create an integer array a[1], a[2], …, a[n]. Then he should perform a sequence of m operations. An operation can be one of the following:
Print operation l, r. Picks should write down the value of .
Modulo operation l, r, x. Picks should perform assignment a[i] = a[i] mod x for each i (l ≤ i ≤ r).
Set operation k, x. Picks should set the value of a[k] to x (in other words perform an assignment a[k] = x).
Can you help Picks to perform the whole sequence of operations?

Input

The first line of input contains two integer: n, m (1 ≤ n, m ≤ 105). The second line contains n integers, separated by space: a[1], a[2], …, a[n] (1 ≤ a[i] ≤ 109) — initial value of array elements.
Each of the next m lines begins with a number type .
If type = 1, there will be two integers more in the line: l, r (1 ≤ l ≤ r ≤ n), which correspond the operation 1.
If type = 2, there will be three integers more in the line: l, r, x (1 ≤ l ≤ r ≤ n; 1 ≤ x ≤ 109), which correspond the operation 2.
If type = 3, there will be two integers more in the line: k, x (1 ≤ k ≤ n; 1 ≤ x ≤ 109), which correspond the operation 3.
Output
For each operation 1, please print a line containing the answer. Notice that the answer may exceed the 32-bit integer.

Examples

input
5 5
1 2 3 4 5
2 3 5 4
3 3 5
1 2 5
2 1 3 3
1 1 3
output
8
5
input
10 10
6 9 6 7 6 1 10 10 9 5
1 3 9
2 7 10 9
2 5 10 8
1 4 7
3 3 7
2 7 9 9
1 2 4
1 6 6
1 5 9
3 1 10
output
49
15
23
1
9

【解题报告】
题目大意是要求维护一棵支持区间取膜,单点更新,区间求和的线段树。
区间取膜看似不好解决,但实际上我们可以发现,每次取膜过后区间内的数至少减半。
所以说在修改操作经过log次之后就不在有效。
直接暴力取膜即可。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100010
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ls rt<<1
#define rs rt<<1|1

struct Node
{
    ll maxx,sum;
}node[N<<2];

void pushup(int rt)
{
    node[rt].maxx=max(node[ls].maxx,node[rs].maxx);
    node[rt].sum=node[ls].sum+node[rs].sum;
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        scanf("%lld",&node[rt].maxx);
        node[rt].sum=node[rt].maxx;
        return;
    }
    int m=(l+r)>>1;
    build(lson);build(rson);
    pushup(rt);
}
void point_update(int index,int k,int l,int r,int rt)
{
    if(l==r)
    {
        node[rt].maxx=k;
        node[rt].sum=k;
        return;
    }   
    int m=(l+r)>>1;
    if(index<=m) point_update(index,k,lson);
    else point_update(index,k,rson);
    pushup(rt);
}
void interval_update(int L,int R,int mod,int l,int r,int rt)
{
    if(L>r||R<l) return;
    if(node[rt].maxx<mod) return;
    if(l==r)
    {
        node[rt].sum%=mod;
        node[rt].maxx=node[rt].sum;
        return;
    }
    int m=(l+r)>>1;
    interval_update(L,R,mod,lson);
    interval_update(L,R,mod,rson);
    pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
    if(L>r||R<l) return 0;
    if(L<=l&&r<=R) return node[rt].sum;
    ll sum=0;
    int m=(l+r)>>1;
    sum+=query(L,R,lson);
    sum+=query(L,R,rson);
    return sum;
}

int n,m;

int main()
{
    scanf("%d%d",&n,&m);
    build(1,n,1);
    while(m--)
    {
        int opt,l,r,mod;
        scanf("%d",&opt);
        if(opt==3)
        {
            scanf("%d%d",&l,&r);
            point_update(l,r,1,n,1);
        }
        if(opt==2)
        {
            scanf("%d%d%d",&l,&r,&mod);
            interval_update(l,r,mod,1,n,1);
        }
        if(opt==1)
        {
            scanf("%d%d",&l,&r);
            printf("%lld\n",query(l,r,1,n,1));
        }
    }
    return 0;
} 
引用\[1\]中提到了一种树形动态规划的方法来解决CodeForces - 982C问题。在这个问题中,subtree指的是子连通块,而不是子树。为了使cnt_white - cnt_black尽可能大,可以使用两次树形动态规划来求解。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。如果ans\[u\]为正,则减去dp\[v\]就是树链所代表的子树的权值。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] 问题: CodeForces - 982C 树形DP是什么问题?如何解决? 回答: CodeForces - 982C是一个树形动态规划问题。在这个问题中,需要求解子连通块的最大权值和,使得cnt_white - cnt_black尽可能大。解决这个问题的方法是使用两次树形动态规划。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] #### 引用[.reference_title] - *1* *2* [CodeForces - 1324F Maximum White Subtree(树形dp)](https://blog.csdn.net/qq_45458915/article/details/104831678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值