题意: 给一个序列,初始全为0,然后有4种操作:

1. 给区间[L,R]所有值+c

2.给区间[L,R]所有值乘c

3.设置区间[L,R]所有值为c

4.查询[L,R]的p次方和(1<=p<=3)

解法: 线段树,维护三个标记,addmark,mulmark,setmark分别表示3种更新,然后p[1],p[2],p[3]分别表示该节点的1,2,3次方和。标记传递顺序setmark一定是第一个,因为setmark可以使mulmark,addmark都失效还原,mulmark和addmark的顺序倒是无所谓。

这题写了半个比赛时间,写的很迷,还是没写出来, 后来看了别人写的,才知道自己很多地方都没更新好甚至没更新。这题算是一道线段树的综合题了,混合了几种常见的更新,对线段树的整体把握很有帮助。

比如:

1.如果setmark有值,那么addmark,mulmark全部要还原。

2.如果mulmark有值,那么addmark也要更新,更新为addmark*mulmark

就是这两点一直没考虑到,WA了好久。

在addmark下传过程中更新p[1],p[2],p[3]的方法如下:

比如 a^3 -> (a+c)^3 的过程:  (a+c)^3 = a^3 + c^3 + 3a*c^2 + 3*a^2*c, a是变量, 所以提取出c,那么p[3]可以由p[1],p[2]推出,p[2]可以由p[1]推出。

即 p[3] = p[3] + c^3 + 3*c^2*p[1] + 3*c*p[2] .

p[2]同理可以由p[1]推出。

然后每次都做一下pushdown,就可以得出正确答案。

当时像优化一下,少做几次pushdown,即这次的操作类型与上次一样就不pushdown,结果那样就会出现问题,还不如每次都pushdown呢。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define Mod 10007
#define SMod 10007
using namespace std;
#define N 100017 struct node{
int p[];
int setmark,addmark,mulmark;
}tree[*N]; void pushup(int rt){
for(int i=;i<=;i++) tree[rt].p[i] = (tree[*rt].p[i] + tree[*rt+].p[i])%SMod;
} void pushdown(int l,int r,int rt)
{
int mid = (l+r)/;
if(tree[rt].setmark)
{
int mk = tree[rt].setmark;
tree[rt<<].setmark = tree[rt<<|].setmark = mk;
tree[rt<<].addmark = tree[rt<<|].addmark = ;
tree[rt<<].mulmark = tree[rt<<|].mulmark = ; tree[rt<<].p[] = (mid-l+)%Mod*mk%SMod;
tree[rt<<|].p[] = (r-mid)%Mod*mk%SMod; tree[rt<<].p[] = (mid-l+)%Mod*mk%SMod*mk%SMod;
tree[rt<<|].p[] = (r-mid)%Mod*mk%SMod*mk%SMod; tree[rt<<].p[] = (mid-l+)%Mod*mk%SMod*mk%SMod*mk%SMod;
tree[rt<<|].p[] = (r-mid)%Mod*mk%SMod*mk%SMod*mk%SMod;
tree[rt].setmark = ;
}
if(tree[rt].mulmark != )
{
int mk = tree[rt].mulmark;
tree[rt<<].mulmark *= mk, tree[rt<<].mulmark%=SMod;
tree[rt<<|].mulmark *= mk, tree[rt<<|].mulmark%=SMod; tree[rt<<].addmark = tree[rt<<].addmark%SMod*mk%SMod;
tree[rt<<|].addmark = tree[rt<<|].addmark%SMod*mk%SMod; tree[rt<<].p[] = tree[rt<<].p[]%Mod*mk%SMod;
tree[rt<<|].p[] = tree[rt<<|].p[]%Mod*mk%SMod; tree[rt<<].p[] = tree[rt<<].p[]%Mod*mk%SMod*mk%SMod;
tree[rt<<|].p[] = tree[rt<<|].p[]%Mod*mk%SMod*mk%SMod; tree[rt<<].p[] = tree[rt<<].p[]%Mod*mk%SMod*mk%SMod*mk%SMod;
tree[rt<<|].p[] = tree[rt<<|].p[]%Mod*mk%SMod*mk%SMod*mk%SMod;
tree[rt].mulmark = ;
}
if(tree[rt].addmark)
{
int mk = tree[rt].addmark;
tree[rt<<].addmark += mk, tree[rt<<].addmark%SMod;
tree[rt<<|].addmark += mk, tree[rt<<|].addmark%SMod; tree[rt<<].p[] = (tree[rt<<].p[]%Mod + (mid-l+)%Mod*mk%SMod*mk%SMod*mk%SMod + *mk%Mod*tree[rt<<].p[]%SMod + *mk%SMod*mk%SMod*tree[rt<<].p[]%SMod)%SMod;
tree[rt<<|].p[] = (tree[rt<<|].p[]%Mod + (r-mid)%Mod*mk%SMod*mk%SMod*mk%SMod + *mk%Mod*tree[rt<<|].p[]%SMod + *mk%SMod*mk%SMod*tree[rt<<|].p[]%SMod)%SMod; tree[rt<<].p[] = (tree[rt<<].p[]%Mod + (mid-l+)%Mod*mk%SMod*mk%SMod + *mk%Mod*tree[rt<<].p[]%SMod)%SMod;
tree[rt<<|].p[] = (tree[rt<<|].p[]%Mod + (r-mid)%Mod*mk%SMod*mk%SMod + *mk%Mod*tree[rt<<|].p[]%SMod)%SMod; tree[rt<<].p[] = (tree[rt<<].p[]%Mod + (mid-l+)%Mod*mk%SMod)%SMod;
tree[rt<<|].p[] = (tree[rt<<|].p[]%Mod + (r-mid)%Mod*mk%SMod)%SMod;
tree[rt].addmark = ;
}
} void build(int l,int r,int rt)
{
tree[rt].setmark = tree[rt].addmark = ;
tree[rt].mulmark = ;
memset(tree[rt].p,,sizeof(tree[rt].p));
if(l == r) return;
int mid = (l+r)/;
build(l,mid,rt<<);
build(mid+,r,rt<<|);
} void update(int l,int r,int aa,int bb,int tag,int val,int rt) //tag = 3 : set 2:mul 1: add
{
if(aa <= l && bb >= r)
{
if(tag == )
{
tree[rt].p[] = (r-l+)%Mod*val%SMod;
tree[rt].p[] = (r-l+)%Mod*val%SMod*val%SMod;
tree[rt].p[] = (r-l+)%Mod*val%SMod*val%SMod*val%SMod;
tree[rt].setmark = val;
tree[rt].addmark = ;
tree[rt].mulmark = ;
}
else if(tag == )
{
tree[rt].p[] = tree[rt].p[]%SMod*val%SMod;
tree[rt].p[] = tree[rt].p[]%SMod*val%SMod*val%SMod;
tree[rt].p[] = tree[rt].p[]%SMod*val%SMod*val%SMod*val%SMod;
tree[rt].mulmark = tree[rt].mulmark%SMod*val%SMod;
tree[rt].addmark = tree[rt].addmark%SMod*val%SMod;
}
else if(tag == )
{
tree[rt].p[] = (tree[rt].p[]%SMod + (r-l+)%SMod*val%SMod*val%SMod*val%SMod + *val%SMod*tree[rt].p[]%SMod + *val%SMod*val%SMod*tree[rt].p[]%SMod)%SMod;
tree[rt].p[] = (tree[rt].p[]%SMod + (r-l+)%SMod*val%SMod*val%SMod + *val%SMod*tree[rt].p[]%SMod)%SMod;
tree[rt].p[] = (tree[rt].p[]%SMod + (r-l+)%SMod*val%SMod)%SMod;
tree[rt].addmark = (tree[rt].addmark+val)%SMod;
}
return;
}
int mid = (l+r)/;
pushdown(l,r,rt);
if(aa <= mid) update(l,mid,aa,bb,tag,val,rt<<);
if(bb > mid) update(mid+,r,aa,bb,tag,val,rt<<|);
pushup(rt);
} int query(int l,int r,int aa,int bb,int i,int rt)
{
if(aa > r || bb < l) return ;
if(aa <= l && bb >= r)
return tree[rt].p[i];
pushdown(l,r,rt);
int res = ;
int mid = (l+r)/;
return (query(l,mid,aa,bb,i,rt<<)%SMod+query(mid+,r,aa,bb,i,rt<<|)%SMod)%SMod;
} int main()
{
int n,m,i,j,op,x,y,c;
while(scanf("%d%d",&n,&m)!=EOF && n+m)
{
build(,n,);
while(m--)
{
scanf("%d%d%d%d",&op,&x,&y,&c);
if(op != ) update(,n,x,y,op,c,);
else printf("%d\n",query(,n,x,y,c,)%SMod);
}
}
return ;
}

HDU 4578 Transformation --线段树,好题的更多相关文章

  1. hdu 4578 Transformation 线段树多种操作裸题

    自己写了一个带结构体的WA了7.8次 但是测了几组小数据都对..感觉问题应该出在模运算那里.写完这波题解去对拍一下. 以后线段树绝不写struct!一般的struct都带上l,r 但是一条线段的长度确 ...

  2. hdu 4578 Transformation 线段树

    没什么说的裸线段树,注意细节就好了!!! 代码如下: #include<iostream> #include<stdio.h> #include<algorithm> ...

  3. Transformation HDU - 4578(线段树——懒惰标记的妙用)

    Yuanfang is puzzled with the question below: There are n integers, a 1, a 2, …, a n. The initial val ...

  4. Transformation 线段树好题 好题 (独立写出来对线段树不容易)

    Transformation Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 65535/65536 K (Java/Others)T ...

  5. HDU 4747 Mex ( 线段树好题 + 思路 )

    参考:http://www.cnblogs.com/oyking/p/3323306.html 相当不错的思路,膜拜之~ 个人理解改日补充. #include <cstdio> #incl ...

  6. hdu 1754 I Hate It 线段树基础题

    Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求, ...

  7. hdu 1754 I Hate It(线段树水题)

    >>点击进入原题测试<< 思路:线段树水题,可以手敲 #include<string> #include<iostream> #include<a ...

  8. HDU 1698 Just a Hook (线段树模板题-区间求和)

    Just a Hook In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of t ...

  9. [AHOI 2009] 维护序列(线段树模板题)

    1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小 ...

随机推荐

  1. MySQL的常规操作

    MySQL的常规知识 show 查看数据库 show databases; 查看表 存在的所有表 show tables; 创建表的命令 show create table table_name; 表 ...

  2. .NET正则表达式匹配Silverlight

    这是一个.NET正则表达式匹配工具的Silverlight 在页面中加入以下代码就可以了: <"> <param name="source" value ...

  3. 百度地图API使用方法详解

    最近做了个项目,其中项目中有个需求需要用到百度地图进行导航,通过查阅相关资料参考百度地图api完成了一个例子. API地址:http://developer.baidu.com/map/jsdemo. ...

  4. Web前端开发工具总结

    前端开发工具: web前端开发乃及其它的相关开发, 推荐sublime text, webstorm(jetbrains公司系列产品)这两个的原因在于,有个技术叫emmet, http://docs. ...

  5. 关于SAP的事务提交和回滚(LUW)

    1 Sap的更新的类型 在sap中,可以使用CALL FUNCTION ... IN UPDATE TASK将多个数据更新绑定到一个database LUW中.程序使用COMMIT WORK提交修改请 ...

  6. mysql不同版本和存储引擎选型的验证

    Mysql的版本和存储引擎较多,为了选择最适合业务使用的系统,需要进行一定的验证,本文描述mysql的验证过程和思路. 主要涉及: Mysql的版本 v Mariadb v Tokudb v Orac ...

  7. Android EditText输入最大值提示功能

    public class LengthFilter implements InputFilter { public LengthFilter(int max) { mMax = max; } @Ove ...

  8. JavaScript学习01 语言简介、基本使用和变量声明

    JavaScript语言简介.基本使用和变量声明 JavaScript是网景(Netscape)公司开发的一种基于客户端浏览器.面向对象.事件驱动式的网页脚本语言. JavaScript的前身叫Liv ...

  9. 遍历collection

    链接 遍历NSArray 正向遍历 for (id object in array) 反向遍历 for (id object in [array reverseObjectEnumerator]) 如 ...

  10. GIT和SVN之间的五个基本区别

    GIT不仅仅是个版本控制系统,它也是个内容管理系统(CMS),工作管理系统等.如果你是一个具有使用SVN背景的人,你需要做一定的思想转换,来适应GIT提供的一些概念和特征.所以,这篇文章的主要目的就是 ...