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.
![](https://oscdn.geek-share.com/Uploads/Images/Content/201511/779a6c86f4db19106cba2c46a7dafe46.jpg)
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
Sample Output
线段树的区间更新问题,其实有模板,不过前提还是得看懂,lazy标记标记的我一醉一醉的。
主要是线段树将一个区间化为了很多子区间,对于单点更新而言时间复杂度logn已经是很小的了,然而对于区间更新我们如果还是按照单点更新的方法去一个个更新复杂度便是nlogn,对于数据量大的题目基本超时,于是就有大牛发明了lazy标记法。
就是说如果在取到了对应区域内的有用线段时,把这个线段整体返回值 (r-l)*(更新的那个数z) 就ok,可是接下来的子段没有加呀!!!如果以后在调用就会出错呀!!!所以我们就将这个线段先标记一下,表示有z是还未传递到子区间的,将标记数组初始化为-1,如果下次要用到这个子区间,我们直接判断子区间标记数组是否为-1,如果是-1就代表这个子区间是未曾懒惰标记的,直接继续算就好,如果有标记不等于-1,那么我们这时再加上标记值也不晚!同时还优化了时间复杂度!区间更新用了lazy标记再次将时间复杂度降低为了logn,减少了n倍呀!!!好方法!
不过还需注意的是线段树题目还是规规矩矩用标准输入输出吧。。。。。这题我用scanf和printf的时间为858ms,规定时间为2000ms,用了cin和cout果然还是会超时的。。。。毕竟输入输出流慢了3倍
![](https://oscdn.geek-share.com/Uploads/Images/Content/201711/cb4e94c34df3079bd70c302064bdba33.gif)
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.
![](https://oscdn.geek-share.com/Uploads/Images/Content/201511/779a6c86f4db19106cba2c46a7dafe46.jpg)
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倍
![](https://oscdn.geek-share.com/Uploads/Images/Content/201711/cb4e94c34df3079bd70c302064bdba33.gif)
#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; }
相关文章推荐
- 线程通信机制
- android-----ANR
- jQuery中的quickExpr
- CPU性能统计数据及Linux监控工具使用
- [Android Studio 权威教程]AS 中配置强大的版本管理系统(Git、SVN、等)
- 数组
- 如何检测远程主机上的某个端口是否开启?
- 【横向滑动】gallery,ViewPager,ViewFlipper
- [Android Studio 权威教程]AS构建系统-Gradle
- 【贪心】NOIP2011day2观光公交
- 关于StringBuffer.setLength和trimToSize
- iOS中获取文件路径的几种方法
- CentOS6.3文字界面下使用yum安装Gnome桌面
- 线程池及例程
- [Android Studio 权威教程]断点调试和高级调试
- 设备模型之kobject,kset及其关系
- [Android Studio 权威教程]AS添加第三方库的6种方式(Jar,module,so等)
- 4.修改更新源sources.list,提高软件下载安装速度(提供Kali 2.0 更新源)
- LeetCode Median of Two Sorted Arrays
- iOS数据库操作之FMDB框架的使用