hdu 4578 Transformation

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

又做了一道好题。。

有三种操作:

1 a b c [a,b]加上c

2 a b c [a,b]乘上c

3 a b c [a,b]变为c

4 a b c 求[a,b]的c次方和(1<=c<=3)

这题首先需要解决的第一个问题是加上或乘上一个数对这个区间的c次方和分别产生什么改变,很简单,一化简就能得到。

第二个问题是当一段区间上既有乘又有加的lazy时应该怎么向下推送,因为一段区间上只能有一个lazy,我起初做的是先将有lazy的标记向下传,直到不冲突为止,然后更新这个区间的lazy,后来无数次的wa。代码太长了,简直无法debug。

同学说要找到这两个lazy的关系,即可以把每个数看做mult * x + add。加上一个数y时,add+= y,乘上一个数y时,mult *= y,add *= y。这样就解决了先加后乘和先乘后加的问题了,感觉好机智,mark。

#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
//#define LL long long
#define LL __int64
#define eps 1e-12
#define PI acos(-1.0)
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 100010;
const int mod = 10007;

struct node
{
    int l,r;
    int mult,add;
    int s[4];
} tree[maxn*4];

void build(int v, int l, int r)
{
	tree[v].l = l;
	tree[v].r = r;
	tree[v].mult = 1;
	tree[v].add = 0;
	tree[v].s[1] = tree[v].s[2] = tree[v].s[3] = 0;
	if(l == r)
		return;
	int mid = (l+r)>>1;
	build(v*2,l,mid);
	build(v*2+1,mid+1,r);
}
void cal(int v,int mult, int add)
{
	int len = tree[v].r - tree[v].l + 1;

	tree[v].s[1] = tree[v].s[1] * mult%mod;
	tree[v].s[2] = tree[v].s[2] * mult%mod*mult%mod;
	tree[v].s[3] = tree[v].s[3] * mult%mod*mult%mod*mult%mod;
	tree[v].mult = (tree[v].mult * mult)%mod;
	tree[v].add = (tree[v].add * mult)%mod;

	tree[v].s[3] = (tree[v].s[3] + 3*add%mod*add%mod*tree[v].s[1]%mod)%mod;
	tree[v].s[3] = (tree[v].s[3] + 3*add%mod*tree[v].s[2]%mod)%mod;
	tree[v].s[3] = (tree[v].s[3] + len*add%mod*add%mod*add%mod)%mod;
	tree[v].s[2] = (tree[v].s[2] + 2*add%mod*tree[v].s[1]%mod)%mod;
	tree[v].s[2] = (tree[v].s[2] + len*add%mod*add%mod)%mod;
	tree[v].s[1] = (tree[v].s[1] + len*add%mod)%mod;
	tree[v].add = (tree[v].add + add)%mod;
}

void push_down(int v)
{
	if(tree[v].l == tree[v].r)
		return;
	cal(v*2,tree[v].mult,tree[v].add);
	cal(v*2+1,tree[v].mult,tree[v].add);
	tree[v].mult = 1;
	tree[v].add = 0;
}

void push_up(int v)
{
	int ls = v*2,rs = v*2+1;
	tree[v].s[1] = (tree[ls].s[1] + tree[rs].s[1])%mod;
	tree[v].s[2] = (tree[ls].s[2] + tree[rs].s[2])%mod;
	tree[v].s[3] = (tree[ls].s[3] + tree[rs].s[3])%mod;
}

void update(int v, int l, int r, int mult, int add)
{
	if(tree[v].l == l && tree[v].r == r)
	{
		cal(v,mult,add);
		return;
	}

	push_down(v);

	int mid = (tree[v].l + tree[v].r) >> 1;

	if(r <= mid)
		update(v*2,l,r,mult,add);
	else if(l > mid)
		update(v*2+1,l,r,mult,add);
	else
	{
		update(v*2,l,mid,mult,add);
		update(v*2+1,mid+1,r,mult,add);
	}
	push_up(v);
}

int query(int v, int l, int r,int p)
{
	if(tree[v].l == l && tree[v].r == r)
	{
		return tree[v].s[p];
	}
	push_down(v);
	int mid = (tree[v].l + tree[v].r) >> 1;
	if(r <= mid)
		return query(v*2,l,r,p);
	else if(l > mid)
		return query(v*2+1,l,r,p);
	else
		return (query(v*2,l,mid,p) + query(v*2+1,mid+1,r,p))%mod;
}

int main()
{
    int n,m;
    int op,x,y,c;
    while(~scanf("%d %d",&n,&m))
    {
        if(n == 0 && m == 0) break;
        build(1,1,n);
        while(m--)
        {
            scanf("%d %d %d %d",&op,&x,&y,&c);
            if(op == 1)
				update(1,x,y,1,c);
			else if(op == 2)
				update(1,x,y,c,0);
			else if(op == 3)
				update(1,x,y,0,c);
            else
                printf("%d\n",query(1,x,y,c)%mod);
        }
    }
    return 0;
}

hdu 4578 Transformation,布布扣,bubuko.com

时间: 2024-10-07 22:54:28

hdu 4578 Transformation的相关文章

HDU 4578 - Transformation - [加强版线段树]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 Problem Description Yuanfang is puzzled with the question below: There are n integers, a1, a2, -, an. The initial values of them are 0. There are four kinds of operations.Operation 1: Add c to each

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

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:因此需优化.可发现题目所有操作都是对区间进行,因此只需要更新 到区间内数字相同即可.

hdu 4578 Transformation(线段树)

Transformation Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 65535/65536 K (Java/Others)Total Submission(s): 3084    Accepted Submission(s): 749 Problem Description Yuanfang is puzzled with the question below: There are n integers, a1, a2,

Hdu 4578 Transformation(区间加值,区间乘值,区间赋值,查询区间的p次方)

Transformation Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 65535/65536 K (Java/Others) Total Submission(s): 4145    Accepted Submission(s): 1027 Problem Description Yuanfang is puzzled with the question below: There are n integers, a1, a

HDU 4578 Transformation --线段树,好题

题意: 给一个序列,初始全为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的顺

HDU 4578 线段树区间更新(确定区间操作的优先级)

HDU 4578 线段树区间更新 操作有: 区间所有数add(c) 区间所有数mul(c) 区间所有数set(c) 查询有: 区间所有数的p次方和(p>= 1 && p <= 3) 关键是区间更新的三种操作的优先级的确定清楚set>mul>add 关键是:down和update中对区间的更新操作是一回事,可以写成函数方便编程 //#pragma warning (disable: 4786) //#pragma comment (linker, "/STA

K - Transformation HDU - 4578 线段树经典题(好题)

题意:区间  加   变成定值 乘  区间查询:和 平方和 立方和 思路:超级超级超级麻烦的一道题  设3个Lazy 标记分别为  change 改变mul乘 add加  优先度change>mul>add因为改变了之后 前面的mul 和add都失效了 push_down的时候    如果有change 标记 可以很方便得求p[1] p[2] p[3] 如果mul存在  则也可以很方便求得子区间的各种值 同时由于mul 比add优先  要把add标记*=value  相当于本来每个加5  乘以

Transformation HDU - 4578 完全平方公式和立方公式展开,有点麻烦

#include<cstdio> #include<cstring> #include<iostream> #include<math.h> using namespace std; const int mod=10007; const int N=100010; struct Node { int l,r; //和 int sum1; //平方和 int sum2; //立方和 int sum3; //要加的数 int lazy1; //要乘的倍数 int

HDU 4578 线段树玄学算法?

Transformation 题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=4578 Problem Description Yuanfang is puzzled with the question below: There are n integers, a1, a2, -, an. The initial values of them are 0. There are four kinds of operations. Operation 1