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想知道这根耳机线的总重量和这根耳机线上颜色的种数。
输入描述:
输出描述:
样例输入:
1000 61 100 1000 1 102 500 6211 7 842 2 102 500 6211 100 347 3 232 120 217
样例输出:
12102420417123031 3
提示:
思路:开两个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);
}
}