山东省赛题 NEU OJ 1444 线段树双标记

http://acm.neu.edu.cn/hustoj/problem.php?id=1444

OJ问题论坛发帖http://t.cn/zjBp4jd FAQ http://t.cn/zjHKbmN Linux问题看http://t.cn/aWnP1n

1444: Devour Magic

时间限制: 1 Sec  内存限制: 256 MB

提交: 129  解决: 21

[提交][状态][讨论版]

题目描述

In Warcraft III, Destroyer is a large flying unit that must consume magic to sustain its mana. Breaking free of the obsidian stone that holds them, these monstrous creatures roar into battle, swallowing magic to feed their insatiable hunger as they move between
battles and rain destruction down upon their foes. Has Spell Immunity. Attacks land and air units.

The core skill of the Destroyer is so called Devour Magic, it takes all mana from all units in a area and gives it to the Destroyer.

Now to simplify the problem, assume you have n units in a line, all unit start with 0 mana and can increase to infinity maximum mana.
All unit except the Destroyer have mana regeneration 1 in per unit time.

The Destroyer have m instructions t l r,
it means, in time t, the Destroyer use Devour Magic on unit from l to r.
We give you all m instructions in time order, count how many mana the Destroyer have devour altogether.

输入

The first line contains one integer T,
indicating the test case. For each test case, the first contains two integer n,?m(1?≤?n,?m?≤?105).
The the next m line each line contains a
instruction t lr.(1?≤?t?≤?105,?1?≤?l?≤?r?≤?n)

输出

For each test case, output the conrespornding result.

样例输入

1
10 5
1 1 10
2 3 10
3 5 10
4 7 10
5 9 10

样例输出

30

提示

来源

山东省赛

写了几次,改了几次,然后最后确定了一种方法:

双标记类的,需要考虑:

1、多个变量标记不同的修改;

2、不同的标记修改的先后次序,我就是这道题,清零和add操作的标记在pushdown的时候次序错误到时一直WA,,,

似乎还是有点疑问,不过对于这道题,每次查询的之前的操作都必然是Add的操作,所以先清零后Add,但是其他题呢??

回头在总结

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <cmath>
#include <map>
#include <queue>
using namespace std;

#define ls(rt) rt*2
#define rs(rt) rt*2+1
#define ll long long
#define rep(i,s,e) for(int i=s;i<e;i++)
#define repe(i,s,e) for(int i=s;i<=e;i++)
#define CL(a,b) memset(a,b,sizeof(a))
#define IN(s) freopen(s,"r",stdin)
#define OUT(s) freopen(s,"w",stdin)

const int MAXN = 100000+10;

struct Node{
    int l,r;
    int add;//标记增量
    int v;
    ll sum;
    int len(){return r-l+1;}
}nodes[MAXN*4];

void build(int rt, int l, int r)
{
    ////////////
    //printf("#build#rt=%d l=%d r=%d\n",rt,l,r);
    ////////////
    nodes[rt].l=l;
    nodes[rt].r=r;
    nodes[rt].sum=nodes[rt].add=0;
    nodes[rt].v=0;
    if(l == r)return;
    int mid=(l+r)/2;
    build(ls(rt),l,mid);
    build(rs(rt),mid+1,r);
    nodes[rt].sum=nodes[ls(rt)].sum+nodes[rs(rt)].sum;
}

void pushdown(int rt)
{
    ///////////
    //printf("#push# rt=%d l=%d r=%d sum=%lld add=%d v=%d\n",rt,nodes[rt].l,nodes[rt].r,nodes[rt].sum,nodes[rt].add,nodes[rt].v);
    if(nodes[rt].v)//放后面因为这个优先级高
    {
        nodes[ls(rt)].add=nodes[rs(rt)].add=0;
        nodes[rs(rt)].sum=nodes[ls(rt)].sum=0;
        nodes[ls(rt)].v=nodes[rs(rt)].v=1;
        nodes[rt].v=0;
    }
    if(nodes[rt].add)
    {
        nodes[ls(rt)].add+=nodes[rt].add;
        nodes[rs(rt)].add+=nodes[rt].add;
        nodes[ls(rt)].sum+=nodes[rt].add*nodes[ls(rt)].len();
        nodes[rs(rt)].sum+=nodes[rt].add*nodes[rs(rt)].len();
        nodes[rt].add=0;
    }

}

//rt的更新在pushdown之前做完,pushdown仅仅更新子节点
void update(int rt, int l, int r, int op)
{
        if(l==nodes[rt].l && nodes[rt].r==r)
        {
            if(op==1)//increase
            {

                nodes[rt].add++;
                nodes[rt].sum+=nodes[rt].len();////////
                //printf("#update# rt=%d l=%d r=%d sum=%lld add=%d\n",rt,l,r,nodes[rt].sum,nodes[rt].add);

            }
            if(op==2)  //clear
            {
                nodes[rt].add=nodes[rt].sum=0;
                nodes[rt].v=1;
            }
            return;
        }
        pushdown(rt);
        int mid=(nodes[rt].l+nodes[rt].r)/2;
        /*if(l<=mid)update(ls(rt),l,r,op);
        if(r>mid)update(rs(rt),l,r,op);*/
        if(r<=mid)update(ls(rt),l,r,op);
        else
        {
            if(l>mid)update(rs(rt),l,r,op);
            else
            {
                update(ls(rt),l,mid,op);
                update(rs(rt),mid+1,r,op);
            }
        }
        nodes[rt].sum=nodes[rs(rt)].sum+nodes[ls(rt)].sum;
}

ll query(int rt, int l, int r)
{
    if(l==nodes[rt].l && nodes[rt].r==r)
    {
        //printf("rt=%d l=%d r=%d sum=%lld\n",rt,l,r,nodes[rt].sum);
        return nodes[rt].sum;
    }
    pushdown(rt);
    int mid=(nodes[rt].l+nodes[rt].r)/2;
    ll tmp1=0;
    /*if(l<=mid)tmp1=query(ls(rt),l,r);
    if(r>mid)tmp2=query(rs(rt),l,r);
    nodes[rt].sum=nodes[rs(rt)].sum+nodes[ls(rt)].sum;*/
    if(r<=mid)tmp1=query(ls(rt),l,r);
    else
    {
        if(l>mid)
            tmp1=query(rs(rt),l,r);
        else
        {
            tmp1=query(ls(rt),l,mid)+query(rs(rt),mid+1,r);
        }
    }
    nodes[rt].sum=nodes[rs(rt)].sum+nodes[ls(rt)].sum;
    return tmp1;
}

struct edge
{
    int l, r;
    int t;
}e[MAXN];

bool cmp(const edge &a, const edge &b)
{
    return a.t<b.t;
}

int main()
{
    int ncase,n,m,l,r,t;
    ll ans;
    scanf("%d",&ncase);
    while(ncase--)
    {
        scanf("%d%d",&n,&m);
        build(1,1,n);

        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&e[i].t,&e[i].l,&e[i].r);
        }
        sort(e,e+m,cmp);
        int time=0;
        ans=0;
        for(int i=0;i<m;i++)
        {
            if(e[i].t>time)
            {
                update(1,1,n,1);
                time=e[i].t;
            }
            ans+=query(1,e[i].l,e[i].r);
            update(1,e[i].l,e[i].r,2);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

山东省赛题 NEU OJ 1444 线段树双标记

时间: 2024-08-26 11:26:51

山东省赛题 NEU OJ 1444 线段树双标记的相关文章

湖南省2016省赛题。1809: Parenthesis 线段树

http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1809 给定一串平衡的序列,要求交换两个位置之后,问其是否还平衡. 首先要注意到交换的是两个位置,这两个位置没有大小之分,所以要判断是否swap他们,保持相对大小 然后如果我们把'('当成是1,把')'当成是-1,那么序列平衡,那么前缀和就是0了. 然后考虑下交换的时候,如果就交换相同的字符,那么肯定是Yes了,如果是')' 和 '(',那么也是Yes 因为本来序列就是平衡的,现在这样交换,只不过

2019徐州网络赛 XKC&#39;s basketball team 线段树

网址:https://nanti.jisuanke.com/t/41387 题意: 大家好,我是训练时长两年半的个人练习生蔡徐坤,我的爱好是唱,跳,rap,篮球. 给出一段长度为$n,(n \leq 1e5)$的序列,对每一个数,求出它和它后面比它大$m$的数中间夹着的数的数量,没有输出$-1$. 题解: 直接建线段树,维护最大值,然后查询时对第$i$个数,搜索区间$[i,n]$之中大于$num[i]+m$的值的位置的最大值,具体操作是先限定区间,然后求出所有合法位置,取最大值,如果搜索不到则返

2016湖南省赛 I Tree Intersection(线段树合并,树链剖分)

2016湖南省赛 I Tree Intersection(线段树合并,树链剖分) 传送门:https://ac.nowcoder.com/acm/contest/1112/I 题意: 给你一个n个结点的树,树上每个节点有自己的颜色 问你删除第i条边后形成的两颗子树有多少个相同的颜色 题解: 树链剖分写法: 对于每一种颜色来说,如果这个颜色是在单独的一颗子树中,那么就不会对其他的边产生贡献,所以我们单独对每一种颜色对边的贡献讨论,如果这个颜色只有一个,那么就不会产生贡献,否则,他就可以在两个相同颜

玲珑oj 1117 线段树+离线+离散化,laz大法

1117 - RE:从零开始的异世界生活 Time Limit:1s Memory Limit:256MByte Submissions:438Solved:68 DESCRIPTION 486到了异世界,看到了一群可爱的妹子比如蕾姆啊,艾米莉亚啊,拉姆啊,白鲸啊,怠惰啊等等!有一天膜女告诉486说她的能力可能不能再用了,因为膜女在思考一个数据结构题,没心情管486了.486说我来帮你做,膜女说你很棒棒哦! 给一个集合,最开始为空(不是数学上的集合)五个操作: 1.插入x2.把小于x的数变成x3

刷题向》关于线段树的区间开根号 BZOJ3211

这是一道关于线段树的区间开根号的裸题,没什么好讲的. 值得注意的是,因为有区间开根号的性质,所以我们每一次更改操作只能把更改区间所覆盖的所有元素全部查找,当然你直接找效率明显爆炸... 能够注意到,指数级别的操作一次更改的数字都很大,而题目的数字最大是10的9次,所以可以注意到的是当一个区间更新6遍以后就失去更新的意义了,因为当你更改次数超过6次所有非负整数数字就全部会化为1.所以可以在每一个节点上加一个类似于LAZY标记的东西,记录开根号次数,以便节约跟新时间. 贴出题目&代码 Descrip

PAT天梯赛练习题 L3-002. 堆栈(线段树查询第K大值)

L3-002. 堆栈 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 大家都知道“堆栈”是一种“先进后出”的线性结构,基本操作有“入栈”(将新元素插入栈顶)和“出栈”(将栈顶元素的值返回并从堆栈中将其删除).现请你实现一种特殊的堆栈,它多了一种操作叫“查中值”,即返回堆栈中所有元素的中值.对于N个元素,若N是偶数,则中值定义为第N/2个最小元:若N是奇数,则中值定义为第(N+1)/2个最小元. 输入格式: 输入第一行给出正整

hihocoder 1586 ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛-题目9 : Minimum【线段树】

https://hihocoder.com/problemset/problem/1586 线段树操作,原来题并不难..... 要求乘积最小只要求区间内最大值.最小值和绝对值小的数,再判断min,max正负就行了. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define lson l,

2019南昌网络赛-I(单调栈+线段树)

题目链接:https://nanti.jisuanke.com/t/38228 题意:定义一段区间的值为该区间的和×该区间的最小值,求给定数组的最大的区间值. 思路:比赛时还不会线段树,和队友在这题上弄了3小时,思路大体都是对的,但就是没法实现.这几天恶补线段树. 首先可以利用单调栈来查找满足a[i]为最小值的最大区间L[i]~R[i].然后利用线段树求一个段的和sum.最小前缀lsum和最小后缀rsum.然后遍历a[i]: a[i]>0:最优为sum(L[i],R[i])*a[i] a[i]<

2019南昌网络赛-I. Yukino With Subinterval 线段树套树状数组

TMD...这题卡内存卡的真优秀... 所以以后还是别用主席树的写法...不然怎么死的都不知道... 树套树中,主席树方法开权值线段树...会造成空间的浪费...这道题内存卡的很紧... 由于树套树已经不需要持久化了,直接动态开点就完事了...用主席树方法开过不去,要么超内存,要么越界... 大概思路...这题要求的[L,R]区间内,满足x<=a[i]<=y的连续的段数, 这题大概是个套路题,我们很容易想到,我们把连续的区间变成单点,把一段区间,类似1 1 1 3 5 变成 1 0 0 3 5