HDU 线段树

给出N个节点,M次操作,和p

每次操作 对l-r区间的每个节点+c,若节点值>=p,则加2*c;

结点存当前区间伤害最小值,最大值,以及lazy操作。更新到如果最小值大于等于P,或者最大值小于P为止。

#include "stdio.h"
#include "string.h"

struct node
{
    int l,r,Min,Max,lazy;
} data[800010];
int p;

int Max(int a,int b)
{
    if (a<b) return b;
    else return a;
}

int Min(int a,int b)
{
    if (a<b) return a;
    else return b;
}

void build(int l,int r,int k)
{
    int mid;
    data[k].l=l;
    data[k].r=r;
    data[k].Min=data[k].Max=data[k].lazy=0;

    if (l==r) return ;

    mid=(l+r)/2;

    build(l,mid,k*2);
    build(mid+1,r,k*2+1);
}

void Pushdown(int k)
{
    if (data[k].l==data[k].r) return ;
    if (data[k].lazy!=0)
    {
        data[k*2].lazy+=data[k].lazy;
        data[k*2].Max+=data[k].lazy;
        data[k*2].Min+=data[k].lazy;
        data[k*2+1].lazy+=data[k].lazy;
        data[k*2+1].Max+=data[k].lazy;
        data[k*2+1].Min+=data[k].lazy;
        data[k].lazy=0;
    }
}
void updata(int l,int r,int k,int op)
{
    int mid;
    if (data[k].l==l && data[k].r==r)
    {
        if (data[k].Max<p)
        {
            data[k].lazy+=op;
            data[k].Max+=op;
            data[k].Min+=op;
            return ;
        }
        if (data[k].Min>=p)
        {
            data[k].lazy+=2*op;
            data[k].Max+=2*op;
            data[k].Min+=2*op;
            return ;
        }

    }

    Pushdown(k);

    mid=(data[k].l+data[k].r)/2;

    if (r<=mid) updata(l,r,k*2,op);
    else if (l>mid) updata(l,r,k*2+1,op);
    else
    {
        updata(l,mid,k*2,op);
        updata(mid+1,r,k*2+1,op);
    }
    data[k].Max=Max(data[k*2].Max,data[k*2+1].Max);
    data[k].Min=Min(data[k*2].Min,data[k*2+1].Min);
}

void query(int k)
{
    if(data[k].l==data[k].r)
    {
        if (data[k].l!=1)
            printf(" %d",data[k].Max);
        else
            printf("%d",data[k].Max);
        return ;
    }
    Pushdown(k);
    query(k*2);
    query(k*2+1);
}

int main()
{
    int n,m,l,r,x;
    while (scanf("%d%d%d",&n,&m,&p)!=EOF)
    {
        build(1,n,1);
        while (m--)
        {
            scanf("%d%d%d",&l,&r,&x);
            updata(l,r,1,x);
        }
        query(1);
        printf("\n");
    }
    return 0;
}
时间: 2024-10-28 14:31:14

HDU 线段树的相关文章

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

哎,又切了一天的水题. 线段树果然必须自己写出来才能叫真正的会了,之前一直在套模板确实不好. 这个题目是单点更新 之 单点增减,= ̄ω ̄= 1 #include <cstdio> 2 3 const int maxn = (1 << 20); 4 5 int n, qL, qR, p, v, sum[maxn]; 6 7 void build(int o, int L, int R) 8 { 9 if(L == R) { scanf("%d", &sum

HDU (线段树 单点更新) I Hate It

和上一道题没什么变化,只不过把单点增减变成了单点替换,把区间求和变成了区间求最大值. 1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 const int maxn = (1 << 20); 6 7 int n, m, qL, qR, p, v; 8 int _max[maxn]; 9 10 void build(int o, int L, int R) 11 { 12 if(L

HDU 1754 I Hate It(线段树之单点更新,区间最值)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 70863    Accepted Submission(s): 27424 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的

HDU 3397 Sequence operation(线段树)

HDU 3397 Sequence operation 题目链接 题意:给定一个01序列,有5种操作 0 a b [a.b]区间置为0 1 a b [a,b]区间置为1 2 a b [a,b]区间0变成1,1变成0 3 a b 查询[a,b]区间1的个数 4 a b 查询[a,b]区间连续1最长的长度 思路:线段树线段合并.须要两个延迟标记一个置为01,一个翻转,然后因为4操作,须要记录左边最长0.1.右边最长0.1,区间最长0.1,然后区间合并去搞就可以 代码: #include <cstdi

hdu 4973 A simple simulation problem.(线段树)

http://acm.hdu.edu.cn/showproblem.php?pid=4973 有两种操作 D l r 将[l,r]区间翻倍 Q l r询问[l,r]中相同数字出现的最多次数 比赛的时候脑子太乱了,没有想到怎么做.发现每次翻倍序列的长度都在变化,区间对应的数也在变,没有思路. 但是静下心来想一想,思路还是挺清晰的. 无论怎么翻倍,序列中的数都是连续的,范围是1~n.可以拿一个数组来记录每个数出现的次数,当更新或询问区间[l,r]时,可以利用其前缀和找到区间[l,r]对应的数字分别是

HDU 4902 Nice boat(线段树)

HDU Nice boat 题目链接 题意:给定一个序列,两种操作,把一段变成x,把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 思路:线段树,每个结点多一个cover表示该位置以下区间是否数字全相同,然后每次延迟操作,最后输出的时候单点查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1

HDU 5172 GTY&#39;s gay friends (线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5172 题意: 给你一个n个数的数组,m次询问,询问在[L, R] 这个区间里面有没有 [1, R-L+1] 的数. 题解: 判断有没有 1 ~ R-L+1 其实就是判断这一段区间和是不是等于 (R-L+1)*(R-L+1+1)/ 2 . 当然还有就是每一个数只能出现1次. 这个问题我们应该怎么解决呢. 我们可以记录第i个数x 的前一个x出现的位置.如果x的前一个x也出现在[L, R]里面,那么这一段

HDU 1556 Color the ball(线段树:区间更新)

http://acm.hdu.edu.cn/showproblem.php?pid=1556 题意: N个气球,每次[a,b]之间的气球涂一次色,统计每个气球涂色的次数. 思路: 这道题目用树状数组和线段树都可以,拿这道题来入门一下线段树的区间更新. 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 const int maxn = 1000

HDU 4902 (线段树)

Problem Nice boat(HDU 4902) 题目大意 维护一个序列,两种操作. 第一种操作,将一段区间[l,r]赋值为x. 第二种操作,将一段区间[l,r]中大于等于x的数与x求gcd. 询问所有操作结束后的序列. 解题分析 用线段树开一个标记same,表示这段区间中的数是否相同,若相同则为该数,否则为-1. 对于第二种操作,对于覆盖区间内的same不为-1的子区间暴力修改. 虽然时限有15s,但貌似跑得挺快的,只用了1s,不知是数据水还是什么缘故. 参考程序 1 #include