nyoj 1217 GLaDOS的耳機

GLaDOS的耳機

時間限制:3000 ms  |  內存限制:65535 KB
難度:4
描述

        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 6
1 100 1000 1 10
2 500 621
1 7 842 2 10
2 500 621
1 100 347 3 23
2 120 217
樣例輸出
1210
2420
4171
23031 3
提示

數據量不小,建議使用scanf()輸入


解題思路:對於輸出重量,就是典型的線段樹區間求和。這裏說一下怎麼求顏色的種類。這裏還是利用線段樹,我們知道越往後添加的顏色越有選擇的權利,即把之前的顏色覆蓋掉,所以我們這裏可以倒着來把顏色添加進來,然後把這一段區間都添1,只要某一種顏色不能找到可以給它添加1的位置,那麼這個顏色就已經被覆蓋掉了。這裏要注意,要開long long,否則WA。。。


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

typedef long long LL;
const int maxn = 80005;
struct Seg
{
	int l,r;
	LL sum,lazy;
}tree[2][maxn<<2];
struct Node
{
	int l,r,c;
}color[maxn];
int n,m,cnt;
bool vis[40005],done;

void build(int rt,int l,int r)
{
	tree[0][rt].l = l, tree[0][rt].r = r;
	tree[1][rt].l = l, tree[1][rt].r = r;
	tree[0][rt].sum = tree[0][rt].lazy = 0;
	tree[1][rt].sum = tree[1][rt].lazy = 0;
	if(l + 1 == r) return;
	int mid = (l + r) >> 1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid,r);
}

void PushDown(int rt)
{
	if(tree[0][rt].lazy)
	{
		tree[0][rt<<1].lazy += tree[0][rt].lazy;
		tree[0][rt<<1].sum += (tree[0][rt<<1].r - tree[0][rt<<1].l) * tree[0][rt].lazy;
		tree[0][rt<<1|1].lazy += tree[0][rt].lazy;
		tree[0][rt<<1|1].sum += (tree[0][rt<<1|1].r - tree[0][rt<<1|1].l) * tree[0][rt].lazy;
		tree[0][rt].lazy = 0;
	}
}

void update(int rt,int l,int r,int val)
{
	if(l <= tree[0][rt].l && tree[0][rt].r <= r)
	{
		tree[0][rt].sum += (tree[0][rt].r - tree[0][rt].l) * val;
		tree[0][rt].lazy += val;
		return;
	}
	PushDown(rt);
	int mid = (tree[0][rt].l + tree[0][rt].r) >> 1;
	if(l < mid) update(rt<<1,l,r,val);
	if(mid < r) update(rt<<1|1,l,r,val);
	tree[0][rt].sum = tree[0][rt<<1].sum + tree[0][rt<<1|1].sum;
}

void update(int rt,int l,int r)
{
	if(tree[1][rt].sum == tree[1][rt].r - tree[1][rt].l) return;
	if(l <= tree[1][rt].l && tree[1][rt].r <= r)
	{
		tree[1][rt].sum = tree[1][rt].r - tree[1][rt].l;
		done = true;
		return;
	}
	int mid = (tree[1][rt].l + tree[1][rt].r) >> 1;
	if(l < mid) update(rt<<1,l,r);
	if(mid < r) update(rt<<1|1,l,r);
	tree[1][rt].sum = tree[1][rt<<1].sum + tree[1][rt<<1|1].sum;
}

LL query(int rt,int l,int r)
{
	if(l <= tree[0][rt].l && tree[0][rt].r <= r)
		return tree[0][rt].sum;
	PushDown(rt);
	LL ans = 0;
	int mid = (tree[0][rt].l + tree[0][rt].r) >> 1;
	if(l < mid) ans += query(rt<<1,l,r);
	if(mid < r) ans += query(rt<<1|1,l,r);
	return ans;
}

int main()
{
	int op,l,r,c,d;
	while(scanf("%d %d",&n,&m)!=EOF)
	{
		build(1,1,n);
		cnt = 0;
		memset(vis,false,sizeof(vis));
		while(m--)
		{
			scanf("%d %d %d",&op,&l,&r);
			if(op == 1)
			{
				scanf("%d %d",&c,&d);
				update(1,l,r,d);
				color[++cnt].l = l, color[cnt].r = r;
				color[cnt].c = c;
			}
			else printf("%lld\n",query(1,l,r));
		}
		int ans = 0;
		for(int i = cnt; i >= 1; i--)
		{
			done = false;
			update(1,color[i].l,color[i].r);
			if(vis[color[i].c] == false)
			{
				if(done == true) 
				{
					ans++;
					vis[color[i].c] = true;
				}
			}
		}
		printf("%lld %d\n",tree[0][1].sum,ans);
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章