题意: 给一个序列,初始全为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. Matter.js – 你不能错过的 2D 物理引擎

    Matter.js 是一个 JavaScript 2D 刚体物理引擎的网页.Matter.Engine 模块包含用于创建和操作引擎的方法.这个引擎是一个管理更新和渲染世界的模拟控制器. Matter. ...

  2. Icon Font浅谈

    这周继续在弄hybird app 的 UI框架的重构,进行到了编写换肤功能的阶段,而在做换肤之前,我想应该先弄一套框架内置的图标. 而图标无非就是两种做法: 1.图片 使用图片很正常,但是有缺陷的. ...

  3. AloneJs —— 简洁高效的JavaScript UI库

    以前做项目时用了一些第三方的JS UI库,项目比较low的时候用还行,一旦项目要求比较高,特别是交互比较复杂时,某些第三方UI库就显得无能为力,用起来也不顺手,改也不好改,所以我就自己基于jQuery ...

  4. JavaScript学习03 JS函数

    JavaScript学习03 JS函数 函数就是包裹在花括号中的代码块,前面使用了关键词function: function functionName() { 这里是要执行的代码 } 函数参数 函数的 ...

  5. Provisioning Profile文件在哪找?

    ~/Library/MobileDevice/Provisioning Profiles

  6. Linux下怎么查看当前系统的版本

    Linux下怎么查看当前系统的版本:   uname -r 功能说明:uname用来获取电脑和操作系统的相关信息. 语 法:uname [-amnrsvpio][--help][--version] ...

  7. JAVA中获取路径

    内容来自于snannan_268 关键字: java中获取路径 JAVA中获取路径: 1.jsp中取得路径:   以工程名为TEST为例: (1)得到包含工程名的当前页面全路径:request.get ...

  8. CMPP错误码说明

    与中国移动代码的对应关系. MI::zzzzSMSC返回状态报告的状态值为EXPIREDMJ:zzzzSMSC返回状态报告的状态值为DELETEDMK:zzzzSMSC返回状态报告的状态值为UNDEL ...

  9. JavaScript Patterns 6.5 Inheritance by Copying Properties

    Shallow copy pattern function extend(parent, child) { var i; child = child || {}; for (i in parent) ...

  10. C#中去掉表中重复的数据

    /// <summary> /// 去掉表中重复的数据  int /// </summary> /// <param name="SourceTable&quo ...