您的位置:首页 > 其它

hdu1698(线段树区间更新)

2015-08-08 12:02 176 查看
Problem Description

In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.



Now Pudge wants to do some operations on the hook.

Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks.

The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows:

For each cupreous stick, the value is 1.

For each silver stick, the value is 2.

For each golden stick, the value is 3.

Pudge wants to know the total value of the hook after performing the operations.

You may consider the original hook is made up of cupreous sticks.

Input

The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases.

For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations.

Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents
the golden kind.

Output

For each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example.

Sample Input

1
10
2
1 5 2
5 9 3


Sample Output

Case 1: The total value of the hook is 24.


线段树的区间更新问题,其实有模板,不过前提还是得看懂,lazy标记标记的我一醉一醉的。

主要是线段树将一个区间化为了很多子区间,对于单点更新而言时间复杂度logn已经是很小的了,然而对于区间更新我们如果还是按照单点更新的方法去一个个更新复杂度便是nlogn,对于数据量大的题目基本超时,于是就有大牛发明了lazy标记法。

就是说如果在取到了对应区域内的有用线段时,把这个线段整体返回值 (r-l)*(更新的那个数z) 就ok,可是接下来的子段没有加呀!!!如果以后在调用就会出错呀!!!所以我们就将这个线段先标记一下,表示有z是还未传递到子区间的,将标记数组初始化为-1,如果下次要用到这个子区间,我们直接判断子区间标记数组是否为-1,如果是-1就代表这个子区间是未曾懒惰标记的,直接继续算就好,如果有标记不等于-1,那么我们这时再加上标记值也不晚!同时还优化了时间复杂度!区间更新用了lazy标记再次将时间复杂度降低为了logn,减少了n倍呀!!!好方法!

不过还需注意的是线段树题目还是规规矩矩用标准输入输出吧。。。。。这题我用scanf和printf的时间为858ms,规定时间为2000ms,用了cin和cout果然还是会超时的。。。。毕竟输入输出流慢了3倍


#include <iostream>
#include<memory.h>
#include<stdio.h>
using namespace std;
const int N=100000;

int tree[N<<2],lazy[N<<2];

void pushdown(int l,int r,int id)
{
if(lazy[id]==-1)return;
lazy[id*2]=lazy[id*2+1]=lazy[id];
int m=(l+r)/2;
tree[id*2]=lazy[id]*(m-l+1);
tree[id*2+1]=lazy[id]*(r-m);
lazy[id]=-1;
}

void update(int l,int r,int z,int ll,int rr,int id)
{
if(l<=ll&&rr<=r)
{
lazy[id]=z;
tree[id]=lazy[id]*(rr-ll+1);
//cout<<"tree"<<ll<<"to"<<rr<<"的值"<<"= "<<tree[id]<<"= lazy[id] "<<lazy[id]<<'*'<<(r-l+1)<<endl;
return;
}
// cout<<ll<<' '<<rr<<' '<<tree[id]<<' '<<lazy[id]<<" id:"<<id<<endl;
pushdown(ll,rr,id);
int m=(ll+rr)/2;
if(m>=l)update(l,r,z,ll,m,id*2);
if(m<r)update(l,r,z,m+1,rr,id*2+1);
tree[id]=tree[id*2]+tree[id*2+1];
// cout<<"tree"<<ll<<"to"<<rr<<"的值"<<tree[id]<<"= "<<"tree"<<ll<<"to"<<m<<"的值"<<tree[id*2]<<'+'<<"tree"<<m+1<<"to"<<rr<<"的值"<<tree[id*2+1]<<endl;
}

int main()
{
int t,o=1;
cin>>t;
while(t--)
{
int n;
int m;
scanf("%d%d",&n,&m);
memset(lazy,-1,sizeof(lazy));
for(int i=1;i<=n*4;i++)
tree[i]=1;
while(m--)
{
int l,r,z;
scanf("%d%d%d",&l,&r,&z);
update(l,r,z,1,n,1);
}
printf("Case %d: The total value of the hook is %d.\n",o++,tree[1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: