HDU 4578 Transformation (线段树区间多种更新)

时间:2022-12-12 20:20:04

http://acm.hdu.edu.cn/showproblem.php?pid=4578

题目大意:对于一个给定序列,序列内所有数的初始值为0,有4种操作。1:区间(x, y)内的所有数字全部加上C;2:区间(x, y)内所有数字全部乘C; 3:区间(x, y)内的所有数字全部重置为C;

4:输出区间(x, y)内所有数字的P次方的和。由于题目为多实例(至少10组样例),故很耿直的更新到叶子节点明显会TLE;因此需优化。可发现题目所有操作都是对区间进行,因此只需要更新

到区间内数字相同即可。再者注意可进行状态压缩,不需要的累加和累乘只标记即可,需要此部分时再往下更新;更新时先更新3,因为3会覆盖掉1和2;之后再进行累乘,因为累乘影响累加,累

加不影响累乘。注意细节即可。

///至少10组样例,则八秒实际上不多,需优化。
///由于所有操作都是对区间进行,故数字保存情况为
///分区间相同,因此只需要操作到区间数字相同时即可,不必处理到最下面的叶子节点
#include <stdio.h>
#include <algorithm>
using namespace std;
#define N 110000
#define mod 10007
#define lson rt<<1
#define rson rt<<1|1
struct tree
{
int l, r, add, mul, op, num;
///add记录累加的数,mul记录累乘的数,op记录操作的状态
///op为1表示区间内数字相同,op为0表示区间内数字不同,需向下
///继续进行操作,op为2表示区间被重新赋值,需向下更新(操作3)。
int len()
{
return r-l+1;
}
}a[N<<2];
void build(int l, int r, int rt)///初始化
{
a[rt].l = l;
a[rt].r = r;
a[rt].mul = a[rt].op = 1;
a[rt].add = a[rt].num = 0;
if(l==r)return ;
int mid = (l+r)/2;
build(l, mid, lson);
build(mid+1, r, rson);
}
void Change(int rt, int op, int k)
{
if(op==3)///重新赋值,即再次初始化
{
a[rt].num = k%mod;
a[rt].mul = 1;
a[rt].add = 0;
a[rt].op = 2;///重新赋值后子区间所有都重新覆盖
}
else if(op==2)
{
(a[rt].add *= k) %= mod;
(a[rt].mul *= k) %= mod;
(a[rt].num *= k) %= mod;
}
else
{
(a[rt].add += k) %= mod;
(a[rt].num += k) %= mod;
}
} void Up(int rt)
{
if(a[lson].op && a[rson].op)///若子区间为同数字区间且两子区间数字相同,
if(a[lson].num == a[rson].num)///则可向上合并给父区间
{
a[rt].num = a[lson].num;
a[rt].op = 1;
}
} void Down(int rt)///向下的状态压缩,若不需此区间作答此区间暂时储存;
{ ///若需此区间作答则向下更新一层直到叶子节点
if(a[rt].l != a[rt].r)
{
if(a[rt].op==2)
{
a[lson].num = a[rson].num = a[rt].num; a[lson].op = a[rson].op = 2;
a[lson].add = a[rson].add = 0;
a[lson].mul = a[rson].mul = 1; a[rt].add = 0;
a[rt].mul = 1;
a[rt].op = 1;
} if(a[rt].mul>1)///注意此处,先更新乘法,因为累乘会影响累加的状态
{
(a[lson].num *= a[rt].mul) %= mod;
(a[lson].add *= a[rt].mul) %= mod;
(a[lson].mul *= a[rt].mul) %= mod; (a[rson].num *= a[rt].mul) %= mod;
(a[rson].add *= a[rt].mul) %= mod;
(a[rson].mul *= a[rt].mul) %= mod; a[rt].mul = 1;
} if(a[rt].add)
{
(a[lson].num += a[rt].add) %= mod;
(a[lson].add += a[rt].add) %= mod; (a[rson].num += a[rt].add) %= mod;
(a[rson].add += a[rt].add) %= mod; a[rt].add = 0;
}
}
}
void Update(int rt, int op, int l, int r, int k)
{
if(a[rt].l==l && a[rt].r==r && a[rt].op)///找到数字相同区间
{
Change(rt, op, k);///执行操作
return ;
} Down(rt);
a[rt].op = 0;///假设默认区间数字已改变,标记为不同。 int mid = (a[rt].l + a[rt].r)/2;
if(mid>=r)Update(lson, op, l, r, k);
else if(mid<l)Update(rson, op, l, r, k);
else
{
Update(lson, op, l, mid, k);
Update(rson, op, mid+1, r, k);
} Up(rt);///执行操作后向上回溯,用已得到的子区间反馈负区间的状态
}
int Query(int rt, int l, int r, int p)
{
if(a[rt].l==l && a[rt].r==r && a[rt].op)///找到同数字区间即可计算
{
int ans = 1;
for(int i=1; i<=p; i++)///一个p次方
(ans *= a[rt].num) %= mod;
ans = (ans * a[rt].len())%mod; ///区间内所有p次方
return ans;
} Down(rt); int mid = (a[rt].l + a[rt].r)/2; if(mid>=r)return Query(lson, l, r, p);
else if(mid<l)return Query(rson, l, r, p);
else
{
int lans = Query(lson, l, mid, p);
int rans = Query(rson, mid+1, r, p);
return (lans+rans)%mod;
}
}
int main()
{
int n, m;
while(scanf("%d %d", &n, &m), m+n)
{
build(1, n, 1);
int op, l, r, k;
while(m--)
{
scanf("%d %d %d %d", &op, &l, &r, &k);
if(op!=4)Update(1, op, l, r, k);///只要不为4都是更新操作
else printf("%d\n", Query(1, l, r, k));
}
}
return 0;
}

HDU 4578 Transformation (线段树区间多种更新)的更多相关文章

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

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

  2. HDU 4578 Transformation --线段树,好题

    题意: 给一个序列,初始全为0,然后有4种操作: 1. 给区间[L,R]所有值+c 2.给区间[L,R]所有值乘c 3.设置区间[L,R]所有值为c 4.查询[L,R]的p次方和(1<=p&lt ...

  3. hdu 4578 Transformation 线段树

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

  4. hdu 4031 attack 线段树区间更新

    Attack Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Subm ...

  5. hdu 5475 An easy problem(暴力 &vert;&vert; 线段树区间单点更新)

    http://acm.hdu.edu.cn/showproblem.php?pid=5475 An easy problem Time Limit: 8000/5000 MS (Java/Others ...

  6. HDU 3308 LCIS &lpar;线段树&amp&semi;&num;183&semi;单点更新&amp&semi;&num;183&semi;区间合并&rpar;

    题意  给你一个数组  有更新值和查询两种操作  对于每次查询  输出相应区间的最长连续递增子序列的长度 基础的线段树区间合并  线段树维护三个值  相应区间的LCIS长度(lcis)  相应区间以左 ...

  7. HDU 3308 LCIS &lpar;线段树区间合并&rpar;

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[ ...

  8. hdu 4747【线段树-成段更新】&period;cpp

    题意: 给出一个有n个数的数列,并定义mex(l, r)表示数列中第l个元素到第r个元素中第一个没有出现的最小非负整数. 求出这个数列中所有mex的值. 思路: 可以看出对于一个数列,mex(r, r ...

  9. hdu 5023(线段树区间染色,统计区间内颜色个数)

    题目描述:区间染色问题,统计给定区间内有多少种颜色? 线段树模板的核心是对标记的处理 可以记下沿途经过的标记,到达目的节点之后一块算,也可以更新的时候直接更新到每一个节点 Lazy操作减少修改的次数( ...

随机推荐

  1. 【代码】二进制转BCD &lbrack;转&rsqb;

    BCD:Binary Coded Decimal 即用4位二进制编码表示1位的十进制数.   定义:BCD码这种编码形式利用了四个位元来储存一个十进制的数码,使二进制和十进制之间的转换得以快捷的进行. ...

  2. 【WP 8&period;1开发】手机客户端应用接收推送通知

    上一篇文章中,已经完成了用于发送通知的服务器端,接下来我们就用这个服务端来测试一下. 在开始测试之前,我们要做一个接收通知的WP应用. 1.启动VS Express for Windows,新建项目, ...

  3. 打包并压缩seajs代码

    背景 seajs是一款优秀的模块开发插件,但是当我们使用它来进行模块化开发的时候,由于它的每个模块的加载都会进行一次http请求,那么当模块数量倍增的时候,会拖慢页面的加载速度. 通常我们为了能加快页 ...

  4. Laravel Predis Error while reading line from the server&period;

    问题 Laravel说明文档中的 Redis 发布与订阅案例,命令行运行php artisan redis:subscribe 到60s自动断开并报错 [Predis\Connection\Conne ...

  5. 一模 (6) day2

    第一题: 题目大意:求最长公共上升子序列(LICS): 解题过程: 1.一开始想到模仿求最长公共子序列的方法,F[i][j]表示A串前i个,B串前j个的最长公共子序列,很明显当A[i]!= B[j]时 ...

  6. Node&period;js &plus;Express&plus;MongoDB&plus;mogoose&plus;ejs&plus;bootstrap&plus;jquery

    Node.js + MongoDB 项目实战(二)  创建项目 在项目实战(一)中,已经配置好了开发环境(详见:http://www.cnblogs.com/jameslong/articles/34 ...

  7. 第一个 spring-boot 程序

    本例使用 maven 作为项目管理工具 新建 pom.xml 文件,添加 spring-boot-starter-web 依赖: <dependency> <groupId>o ...

  8. Python 工厂函数和内建函数

    工厂函数 工厂函数都是类对象, 即当你调用他们时, 创建的其实是一个类实例 例如: str(), list(), tuple()... 内建函数 内建函数通常是python自定义的一些函数, 这些函数 ...

  9. 小程序开发--template模板

    小程序的template模板可以说是我遇到的最简单的了,看看实例: <template name="article"> <view class='containe ...

  10. win10为什么不能把文件直接拖拽