题意: 给一个序列,初始全为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. windows 80 端口占用

    1. cmd 2. regidit 3. 注册表 KEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP'右边有一个'start'的DWORD ...

  2. 深入理解javascript---如何编写高质量的代码?

    如何书写可维护的代码? 最小全局变量 JavaScript通过函数管理作用域.在函数内部声明的变量只在这个函数内部,函数外面不可用.另一方面,全局变量就是在任何函数外面声明的或是未声明直接简单使用的( ...

  3. SharePoint 2013 配置基于AD的Form认证

    前 言 配置SharePoint 2013基于AD的Form认证,主要有三步: 1. 修改管理中心的web.config: 2. 修改STS Application的web.config: 3. 修改 ...

  4. [Dynamics CRM 2016]如何配置多语言显示

    1.安装相对应的语言包并安装 2015语言包下载地址:https://www.microsoft.com/en-us/download/details.aspx?id=45014 2016语言包下载地 ...

  5. 制作CocoaPods依赖库最后步骤修改

    我是看这篇博客http://blog.csdn.net/wzzvictory/article/details/20067595 做的,但是CocoaPods 2015年4月份有了更新,出现了一个tru ...

  6. 转 java中static{}语句块详解

    原文地址:http://blog.csdn.net/lubiaopan/article/details/4802430     感谢原作者! static{}(即static块),会在类被加载的时候执 ...

  7. Android 手机卫士--自定义组合控件构件布局结构

    由于设置中心条目中的布局都很类似,所以可以考虑使用自定义组合控件来简化实现 本文地址:http://www.cnblogs.com/wuyudong/p/5909043.html,转载请注明源地址. ...

  8. Android C代码回调java方法

    本文将讲述下列三种C代码回调java方法 1.c代码回调java空方法 2.c代码回调java int类型参数方法 3.c代码回调javaString类型参数方法 方法都差不多,先看c代码回调java ...

  9. 10个学习Android开发的网站推荐

    1. Android Developers 作为一个Android开发者,官网的资料当然不可错过,从设计,培训,指南,文档,都不应该错过,在以后的学习过程中慢慢理解体会. 2. Android Gui ...

  10. 通过系统架构漏洞获取系统VIP资源

    首先说我的构思: 一本小说,有很多集,每一集请求下载都会生成一个k的json,例如: 有了这个k我们就可以定位到这一集具体的位置,这本小说是固定的id,每一集的K找到了,剩下的不就简单了. 再通过抓包 ...