hdu 4578 Transformation2013杭州邀请赛C(简单线段树)

Transformation

Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 65535/65536 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0


Problem Description
  
  
Yuanfang is puzzled with the question below: There are n integers, a 1, a 2, …, a n. The initial values of them are 0. There are four kinds of operations. Operation 1: Add c to each number between a x and a y inclusive. In other words, do transformation a k<---a k+c, k = x,x+1,…,y. Operation 2: Multiply c to each number between a x and a y inclusive. In other words, do transformation a k<---a k×c, k = x,x+1,…,y. Operation 3: Change the numbers between a x and a y to c, inclusive. In other words, do transformation a k<---c, k = x,x+1,…,y. Operation 4: Get the sum of p power among the numbers between a x and a y inclusive. In other words, get the result of a x p+a x+1 p+…+a y p. Yuanfang has no idea of how to do it. So he wants to ask you to help him.
 

Input
  
  
There are no more than 10 test cases. For each case, the first line contains two numbers n and m, meaning that there are n integers and m operations. 1 <= n, m <= 100,000. Each the following m lines contains an operation. Operation 1 to 3 is in this format: "1 x y c" or "2 x y c" or "3 x y c". Operation 4 is in this format: "4 x y p". (1 <= x <= y <= n, 1 <= c <= 10,000, 1 <= p <= 3) The input ends with 0 0.
 

Output
  
  
For each operation 4, output a single integer in one line representing the result. The answer may be quite large. You just need to calculate the remainder of the answer when divided by 10007.
 

Sample Input
  
  
5 5 3 3 5 7 1 2 4 4 4 1 5 2 2 2 5 8 4 3 5 3 0 0
 

Sample Output
  
  
307 7489

题目大意:n个数,初始值为0,4种操作:

1。将某个区间所有值加上另一个值;

2。将区间所有值都乘上另一个值;

3。将区间所有值置为某个值;

4。查询区间中所有值的p次方和。

题目分析:线段树。

这题其实和这题hdu3397比较类似,不一样的是hdu3397虽然对区间也有3种操作,但是对于每个操作每个区间只有一个逻辑值。而这题就稍微麻烦些,因为有乘法和加法,二者是互斥的,先乘后加和先加后乘是不一样的。所以要维护多个标记。

我在每个节点维护了4个标记,lazy就是普通的区间更新标记,sum表示当前区间的特征值(只有当前区间lazy=1的时候才能用),multi是乘法标记,add是加法标记。

此题要注意的主要有2点:

1,叶子节点初始化的时候lazy置1;

2,无论何时,某个区间的add标记和multi标记只能存在一个,即pushdown的时候,要把子树pushdown。比赛的时候这点WA了几次,还好男神及时指出。

上代码:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<map>
#include<set>
#include<string>
#include<cctype>
#include<vector>
#include<queue>
using namespace std;
const int N = 100005;
const int M = 10000005;
const int mod = 10007;
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1.0);
typedef __int64 ll;

int n,m;
struct node
{
    ll sum;
    int lazy;
    ll multi,add;
}tree[N<<2];

void pushdown(int num)
{
    if(tree[num].lazy)
    {
        tree[num<<1].lazy = tree[num<<1|1].lazy = 1;
        tree[num<<1].sum = tree[num<<1|1].sum = tree[num].sum;
        tree[num<<1].add = tree[num<<1|1].add = 0;
        tree[num<<1].multi = tree[num<<1|1].multi = 1;
        tree[num].lazy = 0;
        return;
    }
    if(tree[num].add)
    {
        if(tree[num<<1].lazy)
        {
            tree[num<<1].sum += tree[num].add;
            tree[num<<1].sum %= mod;
        }
        else
        {
            pushdown(num<<1);
            tree[num<<1].add += tree[num].add;
            tree[num<<1].add %= mod;
        }
        if(tree[num<<1|1].lazy)
        {
            tree[num<<1|1].sum += tree[num].add;
            tree[num<<1|1].sum %= mod;
        }
        else
        {
            pushdown(num<<1|1);
            tree[num<<1|1].add += tree[num].add;
            tree[num<<1|1].add %= mod;
        }
        tree[num].add = 0;
    }
    if(tree[num].multi > 1)
    {
        if(tree[num<<1].lazy)
        {
            tree[num<<1].sum *= tree[num].multi;
            tree[num<<1].sum %= mod;
        }
        else
        {
            pushdown(num<<1);
            tree[num<<1].multi *= tree[num].multi;
            tree[num<<1].multi %= mod;
        }
        if(tree[num<<1|1].lazy)
        {
            tree[num<<1|1].sum *= tree[num].multi;
            tree[num<<1|1].sum %= mod;
        }
        else
        {
            pushdown(num<<1|1);
            tree[num<<1|1].multi *= tree[num].multi;
            tree[num<<1|1].multi %= mod;
        }
        tree[num].multi = 1;
    }
}

void build(int num,int s,int e)
{
    tree[num].add = 0;
    tree[num].multi = 1;
    tree[num].sum = 0;
    tree[num].lazy = 0;
    if(s == e)
    {
        tree[num].lazy = 1;
        return;
    }
    int mid = (s + e)>>1;
    build(num<<1,s,mid);
    build(num<<1|1,mid + 1,e);
}

void update(int num,int s,int e,int l,int r,int val,int op)
{
    if(s == l && r == e)
    {
        if(op == 3)
        {
            tree[num].lazy = 1;
            tree[num].sum = val;
            tree[num].add = 0;
            tree[num].multi = 1;
        }
        else
        {
            if(tree[num].lazy)
            {
                if(op == 1)
                    tree[num].sum += val;
                else
                    tree[num].sum *= val;
                tree[num].sum %= mod;
            }
            else
            {
                pushdown(num);
                if(op == 1)
                {
                    tree[num].add += val;
                    tree[num].add %= mod;
                }
                else
                {
                    tree[num].multi *= val;
                    tree[num].multi %= mod;
                }
            }
        }
        return;
    }
    pushdown(num);
    int mid = (s + e)>>1;
    if(r <= mid)
        update(num<<1,s,mid,l,r,val,op);
    else
    {
        if(l > mid)
            update(num<<1|1,mid + 1,e,l,r,val,op);
        else
        {
            update(num<<1,s,mid,l,mid,val,op);
            update(num<<1|1,mid + 1,e,mid + 1,r,val,op);
        }
    }
}

ll query(int num,int s,int e,int l,int r,int p)
{
    if(s == l && r == e)
    {
        if(tree[num].lazy)
        {
            ll ret = 1;
            while(p --)
            {
                ret *= tree[num].sum;
                ret %= mod;
            }
            ret *= (ll)(e - s + 1);
            ret %= mod;
            return ret;
        }
    }
    pushdown(num);
    int mid = (s + e)>>1;
    if(r <= mid)
        return query(num<<1,s,mid,l,r,p);
    else
    {
        if(l > mid)
            return query(num<<1|1,mid + 1,e,l,r,p);
        else
        {
            return (query(num<<1,s,mid,l,mid,p) + query(num<<1|1,mid + 1,e,mid + 1,r,p)) % mod;
        }
    }
}

int main()
{
    int op,a,b,c;
    while(scanf("%d%d",&n,&m) != EOF)
    {
        if(n == 0 && m == 0)
            break;
        build(1,1,n);
        while(m --)
        {
            scanf("%d%d%d%d",&op,&a,&b,&c);
            if(op <= 3)
                update(1,1,n,a,b,c,op);
            else
                printf("%I64d\n",query(1,1,n,a,b,c)%mod);
        }
    }
    return 0;
}
//4812MS	8492K


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值