J - Assign the task - hdu 3974(多操作混合区间更新)线段树

题意:有四种操作

1,  区间 [l, r] 的值都加上 C

2,  区间 [l, r] 的值都乘上 C

3,  区间 [l, r] 的值都变为C

4,  求区间 [l, r]所有数的p次方的和

分析:是比较麻烦的区间操作,设计四种操作,更新的时候无法更新到底部,不过仔细思考可以想到这都是对区间进行的操作,所以会造成一部分的区间值相等,所以只需要更新到相等区间部分就行了,而且注意有第三种操作的时候,第二和第一种操作可以去掉,操作的优先性是3>2>1,。

WA了一次,因为操作三进行的的时候没有把前两种操作去除

*************************************************************************

#include<algorithm>
#include<stdio.h>
using namespace std;

#define lson u<<1
#define rson u<<1|1

const int MAXN = 1e5+5;
const int mod = 1e4+7;

struct node
{//num表示这个区间的数(区间里面的值都相等,不相等时候为0),mul记录乘的次数,add表示需要加的数

    int l, r, num, mul, add, cover;//cover 等于0的时候表示区间的值不相同,等于1表示区间进行覆盖操作,等于2表示区间的值相同

int m(){return (l+r)>>1;}
    int len(){return r-l+1;}
}a[MAXN<<2];

void Up(int u)
{
    if( a[lson].cover && a[rson].cover )
    if( a[lson].num == a[rson].num )
        a[u].num = a[lson].num, a[u].cover = 2;
}
void Down(int u)
{
    if(a[u].l != a[u].r)
    {
        if( a[u].cover == 1 )
        {
            a[lson].cover = a[rson].cover = 1;
            a[lson].num = a[rson].num = a[u].num;
            a[lson].add = a[rson].add = 0;
            a[lson].mul = a[rson].mul = 1;

a[u].cover = 2, a[u].mul = 1, a[u].add = 0;
        }
        if( a[u].mul > 1 )
        {
            (a[lson].mul *= a[u].mul)%=mod, (a[rson].mul *= a[u].mul)%=mod;
            (a[lson].num *= a[u].mul)%=mod, (a[rson].num *= a[u].mul)%=mod;
            (a[lson].add *= a[u].mul)%=mod, (a[rson].add *= a[u].mul)%=mod;

a[u].mul = 1;
        }

if( a[u].add )
        {
            (a[lson].add += a[u].add)%=mod, (a[rson].add += a[u].add)%=mod;
            (a[lson].num += a[u].add)%=mod, (a[rson].num += a[u].add)%=mod;

a[u].add = 0;
        }
    }
}
void Build(int u, int l, int r)
{
    a[u].add = 0, a[u].cover = 2, a[u].mul = 1;
    a[u].num = 0, a[u].l = l, a[u].r = r;

if(l == r)
        return ;

Build(lson, l, a[u].m());
    Build(rson, a[u].m()+1, r);
}
void Insert(int u, int l, int r, int op, int val)
{
    if(a[u].l == l && a[u].r == r && a[u].cover)
    {
        if(op == 3)
            a[u].add=0, a[u].cover = 1, a[u].mul = 1, a[u].num = val;
        else if(op == 2)
            (a[u].mul *= val)%=mod, (a[u].add *= val)%=mod, (a[u].num *= val)%=mod;
        else
            (a[u].add += val)%=mod, (a[u].num += val)%=mod;

return ;
    }

Down(u); a[u].cover = 0;

if(r <= a[u].m())
        Insert(lson, l, r, op, val);
    else if(l > a[u].m())
        Insert(rson, l, r, op, val);
    else
    {
        Insert(lson, l, a[u].m(), op, val);
        Insert(rson, a[u].m()+1, r, op, val);
    }

Up(u);
}
int  Query(int u, int l, int r, int p)
{

if(a[u].l == l && a[u].r == r && a[u].cover)
    {
        int ans = 1;
        while(p--) (ans *= a[u].num)%=mod;
        ans = (ans * a[u].len())%mod;

return ans;
    }

Down(u);

if(r <= a[u].m())
        return Query(lson, l, r, p);
    else if(l > a[u].m())
        return Query(rson, l, r, p);
    else
    {
        int lsum = Query(lson, l, a[u].m(), p);
        int rsum = Query(rson, a[u].m()+1, r, p);

return (lsum+rsum) % mod;
    }
}

int  main()
{
    int N, M;

while(scanf("%d%d", &N, &M), N+M)
    {
        int u, v, op, c;

Build(1, 1, N);

while(M--)
        {
            scanf("%d%d%d%d", &op, &u, &v, &c);

if(op != 4)
                Insert(1, u, v, op, c);
            else
                printf("%d\n", Query(1, u, v, c));
        }
    }

return 0;}

时间: 2024-10-11 21:39:15

J - Assign the task - hdu 3974(多操作混合区间更新)线段树的相关文章

J - Assign the task HDU - 3974 (线段树 + dfs序)

题意:给一颗树,两种操作,查询 i 结点的颜色,和将i结点和它的子树都染成另一种颜色 题解:dfs序构建线段树,对于x和其子树染色就是 l[x] 和 r[x]; dfs序线段树板子 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<queue>

hdu 1166 敌兵布阵(单点更新线段树)

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 54411    Accepted Submission(s): 22830 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

J - Assign the task

J - Assign the task HDU - 3974 思路:一眼秒思路<(* ̄▽ ̄*)/ dfs序+线段树. 通过dfs序把树上问题转化成线段上的问题.然后用线段树解决. 错因:都是些zz的错误就不说了 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 50010 using namespace std; int t,n,

HDU 1823 Luck and Love 二维线段树

Problem Description 世界上上最远的距离不是相隔天涯海角 而是我在你面前 可你却不知道我爱你 ―― 张小娴 前段日子,枫冰叶子给Wiskey做了个征婚启事,聘礼达到500万哦,天哪,可是天文数字了啊,不知多少MM蜂拥而至,顿时万人空巷,连扫地的大妈都来凑热闹来了.―_―||| 由于人数太多,Wiskey实在忙不过来,就把统计的事情全交给了枫冰叶子,自己跑回家休息去了.这可够枫冰叶子忙的了,他要处理的有两类事情,一是得接受MM的报名,二是要帮Wiskey查找符合要求的MM中缘分最

HDU 1540 &amp;&amp; POJ 2892 Tunnel Warfare (线段树,区间合并).

~~~~ 第一次遇到线段树合并的题,又被律爷教做人.TAT. ~~~~ 线段树的题意都很好理解吧.. 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1540 http://poj.org/problem?id=2892 ~~~~ 我的代码:200ms #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #defin

HDU 4027 Can you answer these queries? (线段树+区间点修改)

题意:给你 n 个数,m个询问(c,x,y) c==0 把x,y区间的值变为原来的平方根(向下取整) c==1 计算x,y区间的和. 利用1的开方永远为1剪枝.. #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> //#include<map> #include<cmath> #include<iostream> #include

HDU 4027 Can you answer these queries?(线段树,区间更新,区间查询)

题目 线段树 简单题意: 区间(单点?)更新,区间求和 更新是区间内的数开根号并向下取整 这道题不用延迟操作 //注意: //1:查询时的区间端点可能前面的比后面的大: //2:优化:因为每次更新都是开平方,同一个数更新有限次数就一直是1了,所以可以这样优化 #include <stdio.h> #include<math.h> #define N 100010 #define LL __int64 #define lson l,m,rt<<1 #define rson

HDU 5371 Hotaru&#39;s problem manacher+(线段树or set)

题意,给定一个100000 的串,求他一个子串,使得将子串分成三部分有后,第一部分=第三部分,第一部分与第二部分对称(回文) 首先我们需要处理出以i为轴的回文串的两端,这个事情可以用Manacher算法完成,复杂度O(n) http://blog.csdn.net/ggggiqnypgjg/article/details/6645824/ 这个博客写的很好懂.不会的童鞋可以去学习一下这个算法,非常精妙. 好的现在我们已经会了这个算法,并获得了每个点为轴的串的右端点p[i] 很简单地可以处理出左端

HDU 4942 Game on S♂play(线段树、模拟、扩栈)

比赛的时候想到这题的大概做法,但由于卡别的水题...就赛后做了... 题意:给一个二叉树,每个结点有一个w[i],有3种操作,0 x表示左旋x,1 x表示右旋x,3 x表示询问x结点的价值,其中,价值为x子树结点的累加价值的累乘,其中,结点的累加价值为结点子树的Σw[i].即询问是,∏Σw. 好像题意被我说得好渣好乱....还是忽略上面2行吧... 首先,左旋右旋不影响中序遍历的index,即,可以把题目那2个图进行中序遍历,结果都是αXβYγ.由此,可以建立线段树. 而左旋右旋的过程模拟即可,