题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578  , 线段树的区间更新 + 多种操作,好题。

  虽然是比较裸的线段树,但是比较麻烦,并且有很多细节需要考虑,最后我7.3s很惊险地过了,求大神告知优化方法。


  这道题坑在有三种询问:set , add , mul。所以lazy标记要有三个,如果三个标记同时出现的处理方法——当更新set操作时,就把add标记和mul标记全部取消;当更新mul操作时,如果当前节点add标记存在,就把add标记改为:add * mul。这样的话就可以在PushDown()操作中先执行set,然后mul,最后add。

  麻烦在有三种询问:和 , 平方和 , 立方和。对于set和mul操作来说,这三种询问都比较好弄。

  对于add操作,和的话就比较好弄,按照正常方法就可以;

  平方和这样来推:(a + c)2 = a2 + c2 + 2ac  , 即sum2[rt] = sum2[rt] + (r - l + 1) * c * c + 2 * sum1[rt] * c;

  立方和这样推:(a + c)3 = a3 + c3 + 3a(a2 + ac) , 即sum3[rt] = sum3[rt] + (r - l + 1) * c * c * c + 3 * c * (sum2[rt] + sum1[rt] * c);

  几个注意点:add标记取消的时候是置0,mul标记取消的时候是置1;在PushDown()中也也要注意取消标记,如set操作中取消add和mul,mul操作中更新add; 在add操作中要注意sum3 , sum2 , sum1的先后顺序,一定是先sum3 , 然后sum2 , 最后sum1; int容易爆,还是用LL要保险一点; 最后就是运算较多,不要漏掉东西。

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL __int64
#define eps 1e-8
#define INF INT_MAX
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int MOD = ;
const int maxn = + ;
const int N = ;
LL add[maxn << ] , set[maxn << ] , mul[maxn << ];
LL sum1[maxn << ] , sum2[maxn << ] , sum3[maxn << ];
void PushUp(int rt)
{
sum1[rt] = (sum1[rt << ] + sum1[rt << | ]) % MOD;
sum2[rt] = (sum2[rt << ] + sum2[rt << | ]) % MOD;
sum3[rt] = (sum3[rt << ] + sum3[rt << | ]) % MOD;
}
void build(int l , int r , int rt)
{
add[rt] = set[rt] = ;
mul[rt] = ;
if(l == r) {
sum1[rt] = sum2[rt] = sum3[rt] = ;
return;
}
int m = (l + r) >> ;
build(lson);
build(rson);
PushUp(rt);
}
void PushDown(int rt , int len)
{
if(set[rt]) {
set[rt << ] = set[rt << | ] = set[rt];
add[rt << ] = add[rt << | ] = ; //注意这个也要下放
mul[rt << ] = mul[rt << | ] = ;
LL tmp = ((set[rt] * set[rt]) % MOD) * set[rt] % MOD;
sum1[rt << ] = ((len - (len >> )) % MOD) * (set[rt] % MOD) % MOD;
sum1[rt << | ] = ((len >> ) % MOD) * (set[rt] % MOD) % MOD;
sum2[rt << ] = ((len - (len >> )) % MOD) * ((set[rt] * set[rt]) % MOD) % MOD;
sum2[rt << | ] = ((len >> ) % MOD) * ((set[rt] * set[rt]) % MOD) % MOD;
sum3[rt << ] = ((len - (len >> )) % MOD) * tmp % MOD;
sum3[rt << | ] = ((len >> ) % MOD) * tmp % MOD;
set[rt] = ;
}
if(mul[rt] != ) { //这个就是mul[rt] != 1 , 当时我这里没注意所以TLE了
mul[rt << ] = (mul[rt << ] * mul[rt]) % MOD;
mul[rt << | ] = (mul[rt << | ] * mul[rt]) % MOD;
if(add[rt << ]) //注意这个也要下放
add[rt << ] = (add[rt << ] * mul[rt]) % MOD;
if(add[rt << | ])
add[rt << | ] = (add[rt << | ] * mul[rt]) % MOD;
LL tmp = (((mul[rt] * mul[rt]) % MOD * mul[rt]) % MOD);
sum1[rt << ] = (sum1[rt << ] * mul[rt]) % MOD;
sum1[rt << | ] = (sum1[rt << | ] * mul[rt]) % MOD;
sum2[rt << ] = (sum2[rt << ] % MOD) * ((mul[rt] * mul[rt]) % MOD) % MOD;
sum2[rt << | ] = (sum2[rt << | ] % MOD) * ((mul[rt] * mul[rt]) % MOD) % MOD;
sum3[rt << ] = (sum3[rt << ] % MOD) * tmp % MOD;
sum3[rt << | ] = (sum3[rt << | ] % MOD) * tmp % MOD;
mul[rt] = ;
}
if(add[rt]) {
add[rt << ] += add[rt]; //add是+= , mul是*=
add[rt << | ] += add[rt];
LL tmp = (add[rt] * add[rt] % MOD) * add[rt] % MOD; //注意sum3 , sum2 , sum1的先后顺序
sum3[rt << ] = (sum3[rt << ] + (tmp * (len - (len >> )) % MOD) + * add[rt] * ((sum2[rt << ] + sum1[rt << ] * add[rt]) % MOD)) % MOD;
sum3[rt << | ] = (sum3[rt << | ] + (tmp * (len >> ) % MOD) + * add[rt] * ((sum2[rt << | ] + sum1[rt << | ] * add[rt]) % MOD)) % MOD;
sum2[rt << ] = (sum2[rt << ] + ((add[rt] * add[rt] % MOD) * (len - (len >> )) % MOD) + ( * sum1[rt << ] * add[rt] % MOD)) % MOD;
sum2[rt << | ] = (sum2[rt << | ] + (((add[rt] * add[rt] % MOD) * (len >> )) % MOD) + ( * sum1[rt << | ] * add[rt] % MOD)) % MOD;
sum1[rt << ] = (sum1[rt << ] + (len - (len >> )) * add[rt]) % MOD;
sum1[rt << | ] = (sum1[rt << | ] + (len >> ) * add[rt]) % MOD;
add[rt] = ;
}
}
void update(int L , int R , int c , int ch , int l , int r , int rt)
{
if(L <= l && R >= r) {
if(ch == ) {
set[rt] = c;
add[rt] = ;
mul[rt] = ;
sum1[rt] = ((r - l + ) * c) % MOD;
sum2[rt] = ((r - l + ) * ((c * c) % MOD)) % MOD;
sum3[rt] = ((r - l + ) * (((c * c) % MOD) * c % MOD)) % MOD;
} else if(ch == ) {
mul[rt] = (mul[rt] * c) % MOD;
if(add[rt])
add[rt] = (add[rt] * c) % MOD;
sum1[rt] = (sum1[rt] * c) % MOD;
sum2[rt] = (sum2[rt] * (c * c % MOD)) % MOD;
sum3[rt] = (sum3[rt] * ((c * c % MOD) * c % MOD)) % MOD;
} else if(ch == ) {
add[rt] += c;
LL tmp = (((c * c) % MOD * c) % MOD * (r - l + )) % MOD; //(r - l + 1) * c^3
sum3[rt] = (sum3[rt] + tmp + * c * ((sum2[rt] + sum1[rt] * c) % MOD)) % MOD;
sum2[rt] = (sum2[rt] + (c * c % MOD * (r - l + ) % MOD) + * sum1[rt] * c) % MOD;
sum1[rt] = (sum1[rt] + (r - l + ) * c) % MOD;
}
return;
}
PushDown(rt , r - l + );
int m = (l + r) >> ;
if(L > m)
update(L , R , c , ch , rson);
else if(R <= m)
update(L , R , c , ch , lson);
else {
update(L , R , c , ch , lson);
update(L , R , c , ch , rson);
}
PushUp(rt);
}
LL query(int L , int R , int p , int l , int r , int rt)
{
if(L <= l && R >= r) {
if(p == )
return sum1[rt] % MOD;
else if(p == )
return sum2[rt] % MOD;
else
return sum3[rt] % MOD;
}
PushDown(rt , r - l + );
int m = (l + r) >> ;
if(L > m)
return query(L , R , p , rson);
else if(R <= m)
return query(L , R , p , lson);
else
return (query(L , R , p , lson) + query(L , R , p , rson)) % MOD;
}
int main()
{
int n , m;
int a , b , c , ch;
while(~scanf("%d %d" , &n , &m))
{
if(n == && m == )
break;
build( , n , );
while(m--) {
scanf("%d %d %d %d" , &ch , &a , &b , &c);
if(ch != ) {
update(a , b , c , ch , , n , );
} else {
printf("%I64d\n" , query(a , b , c , , n , ));
}
}
}
return ;
}

HDU4578 线段树(区间更新 + 多种操作)的更多相关文章

  1. HDU4578 线段树(区间更新 + 多种操作)和平方,立方

    参考:https://www.cnblogs.com/H-Vking/p/4297973.html 题意: 虽然是比较裸的线段树,但是比较麻烦,并且有很多细节需要考虑,对着别人的ac代码debug了一 ...

  2. hdu4578线段树区间更新

    /* 只有在区间中的数字不相同时才pushdown:往子区间传递数字再到子区间更新,同时该区间的flag置0 更新完左右子区间后进行pushup,如果左右子区间数字相同,那么把子区间合并,子区间数字置 ...

  3. hihoCoder 1080 : 更为复杂的买卖房屋姿势 线段树区间更新

    #1080 : 更为复杂的买卖房屋姿势 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho都是游戏迷,“模拟都市”是他们非常喜欢的一个游戏,在这个游戏里面他们 ...

  4. HDU 5023 A Corrupt Mayor's Performance Art(线段树区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5023 解题报告:一面墙长度为n,有N个单元,每个单元编号从1到n,墙的初始的颜色是2,一共有30种颜色 ...

  5. HDU 4902 Nice boat 2014杭电多校训练赛第四场F题(线段树区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4902 解题报告:输入一个序列,然后有q次操作,操作有两种,第一种是把区间 (l,r) 变成x,第二种是 ...

  6. HDU5039--Hilarity DFS序+线段树区间更新 14年北京网络赛

    题意:n个点的树,每个条边权值为0或者1, q次操作 Q 路径边权抑或和为1的点对数, (u, v)(v, u)算2个. M i修改第i条边的权值 如果是0则变成1, 否则变成0 作法: 我们可以求出 ...

  7. hihoCoder #1078 : 线段树的区间修改(线段树区间更新板子题)

    #1078 : 线段树的区间修改 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于小Ho表现出的对线段树的理解,小Hi表示挺满意的,但是满意就够了么?于是小Hi将问题 ...

  8. hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...

  9. POJ 3468:A Simple Problem with Integers(线段树区间更新模板)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 141093 ...

随机推荐

  1. springboot整合mybatis分页插件PageHelper

    1 pom文件引入依赖 (注意:pagehelper版本不能太高,楼主之前用的5.0以上的版本,然后分页没有效果,浪费了两个小时才发现这个原因) <!-- mybatis的分页插件 --> ...

  2. HDOJ 5019 Revenge of GCD

    Revenge of GCD In mathematics, the greatest common divisor (gcd), also known as the greatest common ...

  3. Java Calendar Date使用总结

    Java Calendar Date使用总结 package cn.outofmemory.codes.Date; import java.util.Calendar; import java.uti ...

  4. WCF 4.0 如何编程修改wcf配置,不使用web.config静态配置

    How to programmatically modify WCF without web.config setting WCF 4.0 如何编程修改wcf配置,不使用web.config静态配置 ...

  5. java技术秘籍 转摘

  6. java EE 新手入门了解

    郑重申明:本文转载至https://blog.csdn.net/Neuf_Soleil/article/details/80962686,在此深表感谢! 为什么选择java? 想必有很多初学者会像我一 ...

  7. Java的文档注释之生成帮助文档

    示例: /** * Title: Person类<br/> * Description:通过Person类说明Java中的文档注释<br/> * Company: *** * ...

  8. Java 社区论坛 - Sym 1.5.0 发布

    简介 Sym 是一个用 Java 写的实时论坛,欢迎来 体验!(如果你需要搭建一个企业内网论坛,请使用 SymX) 非常详细的 Sym 功能点脑图 如果你在搭建或者二次开发时碰到问题,欢迎加 Q 群 ...

  9. apm飞控飞行模式详解

    1.稳定模式Stabilize稳定模式是使用得最多的飞行模式,也是最基本的飞行模式,起飞和降落都应该使用此模式.此模式下,飞控会让飞行器保持稳定,是初学者进行一般飞行的首选,也是FPV第一视角飞行的最 ...

  10. OFDM正交频分复用---基础入门图示

    @(162 - 信号处理) 整理转载自:给小白图示讲解OFDM 下面以图示为主讲解OFDM,以"易懂"为第一要义. 注:下面的讨论如果不做说明,均假设为理想信道. *** 一张原理 ...