nyoj 1217 GLaDOS的耳机(线段树,开两个标记数组维护)

本文介绍了一个基于线段树的数据结构问题——GLaDOS的耳机升级挑战。该问题涉及耳机线上的操作,包括涂漆及查询重量等,并通过线段树来高效地解决这些操作。

  • 1217-GLaDOS的耳机


  • 内存限制:64MB时间限制:3000msSpecial Judge: No

  • accepted:8submit:40


题目描述:

       GLaDOS是个耳机控。对于他来说,已经不满足于只是听出供电设备是水电、核电还是火电了。GLaDOS有更大的目标,他想听出宇宙中最神秘的代号为"Y_A_FL"的声音。为了实现这个目的,GLaDOS决定为他的耳机加工升级。但是笨手笨脚的GLaDOS表示加工升级神马的太困难了。于是GLaDOS想请JX为他解决这个难题,而懒得不能再懒得JX又把这个难题交给了你,你能帮这两个二货解决这个问题么?
       
现在,给你一个n,表示耳机上有n个点,相邻的每两个点间距为1单位长度。从左往右,每个点的编号分别为1,2,3...n。GLaDOS想要对这条耳机线进行m次操作。对于这条耳机线,GLaDOS有两种操作:
        
⊙ 1 L R c d代表着GLaDOS想要为这条耳机线从L点到R点的这段区间上涂一层金属漆(1<=L,R<=n)金属漆的颜色为c(0<=c<=40000),新涂的金属漆会将原有的金属漆覆盖,每单位长度的金属漆重量为d(0<d<=1000)(最初耳机线的重量为0,没有颜色)。
        
⊙ 2 L R 代表着GLaDOS想要知道耳机线在L点到R点这段区间内的重量。

 m次操作结束之后,GLaDOS想知道这根耳机线的总重量和这根耳机线上颜色的种数。


输入描述:

输入包含多组数据(最多11组)每组数据的第一行是两个整数n,m(2<=n,m<=80000)分别表示耳机长度和GLaDOS的操作次数。接着是m行,每行一个操作。

输出描述:

每组数据对于每个操作2,你都将输出1个整数,代表着在L到R这段区间内的耳机线的重量。每组数据的最后一行,输出耳机的总重量和颜色种数。

样例输入:

1000 61 100 1000 1 102 500 6211 7 842 2 102 500 6211 100 347 3 232 120 217

样例输出:

12102420417123031 3


提示:

数据量不小,建议使用scanf()输入

思路:开两个lazy数组一个维护耳机的重量,另一个维护颜色值,重量应该是累加的,而耳机的值则是直接覆盖。关键是最后怎么统计颜色的种类,如建树一般跑一遍,以便确定每一段的颜色值,用vis数组标记一下,最后遍历所有的颜色值,标记过的就加一,最后输出即可。这题还要注意的是区间更新的是线段,而不是每一个点(比如说三个点只有两条线段,而这里要更新的是这两条线段而不是三个点)

比赛时纠结的是颜色种类怎么统计,想到了开两个标记数组,但当时想边更新边统计颜色数量,最后还是没写成,刚学线段树,以后还要多练练。

详细请看代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
using namespace std;
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long LL;
const int mod=1e9+7;
const double pi=acos(-1);
const double eps=1e-8;
const int N=8e4+10;
LL sum[N<<2],lazy[N<<2];//重量以及重量标记
LL color[N<<2],clazy[N<<2];//颜色值以及颜色标记
bool vis[N>>1];
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int ln,int rn)
{
    if(lazy[rt])//重量累加
    {
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        sum[rt<<1]+=lazy[rt]*ln;
        sum[rt<<1|1]+=lazy[rt]*rn;
        lazy[rt]=0;
    }
    if(clazy[rt]!=-1)//颜色值直接覆盖
    {
        clazy[rt<<1]=clazy[rt];
        clazy[rt<<1|1]=clazy[rt];
        color[rt<<1]=clazy[rt];
        color[rt<<1|1]=clazy[rt];
        clazy[rt]=-1;
    }
}
void build(int l,int r,int rt)
{
    color[rt]=-1;
    clazy[rt]=-1;
    lazy[rt]=0;
    sum[rt]=0;
    if(l==r) return ;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int L,int R,int c,int d,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        lazy[rt]+=(LL)c;
        sum[rt]+=(LL)c*(r-l+1);
        clazy[rt]=(LL)d;
        color[rt]=(LL)d;
        return ;
    }
    int m=(l+r)>>1;
    pushdown(rt,m-l+1,r-m);
    if(L<=m) update(L,R,c,d,lson);
    if(R>m) update(L,R,c,d,rson);
    pushup(rt);
}
LL query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
        return sum[rt];
    int m=(l+r)>>1;
    LL ans=0;
    pushdown(rt,m-l+1,r-m);
    if(L<=m) ans+=query(L,R,lson);
    if(R>m) ans+=query(L,R,rson);
    return ans;
}
void build_color(int l,int r,int rt)//确定每一段区间的颜色值
{
    if(l==r)
    {
        vis[color[rt]]=true;
        return ;
    }
    int m=(l+r)>>1;
    pushdown(rt,m-l+1,r-m);
    build_color(lson);
    build_color(rson);
}
int main()
{
    int m,n,op,a,b,c,d,cnt;
    while(~scanf("%d%d",&n,&m))
    {
        cnt=0;
        mem(vis,false);
        build(1,n,1);
        while(m--)
        {
            scanf("%d%d%d",&op,&a,&b);
            a++;//这里更新的是线段,n个点构成n-1条线段,所以让a++
            if(op==2) printf("%lld\n",query(a,b,1,n,1));
            else
            {
                scanf("%d%d",&c,&d);
                update(a,b,d,c,1,n,1);
            }
        }
        build_color(1,n,1);
        for(int i=0;i<=40000;i++)//遍历所有颜色值,统计
            if(vis[i]) cnt++;
        printf("%lld %d\n",query(1,n,1,n,1),cnt);
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值