HDU  1698

链接:  http://acm.hdu.edu.cn/showproblem.php?pid=1698

线段树功能:update:成段替换 (由于只query一次总区间,所以可以直接输出1结点的信息)

<span style="font-size:18px;">#include<iostream>
#include<cstdio>
#include<cstring>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn=100001;
int sum[maxn<<2];
int col[maxn<<2];
void pushUP(int rt) //当前节点信息更新给父节点
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int m) //当前节点信息更新给儿子节点
{
if(col[rt])
{
col[rt<<1]=col[rt<<1|1]=col[rt];
sum[rt<<1]=(m-(m>>1))*col[rt];
sum[rt<<1|1]=(m>>1)*col[rt];
col[rt]=0;
}
}
void build(int l,int r,int rt) //建立线段树
{
col[rt]=0;
sum[rt]=1;
if(l==r)
return;
int m=(l+r)/2;
build(lson);
build(rson);
pushUP(rt);
}
void update(int L,int R,int c,int l,int r,int rt) //成段替换,由于只query一次总区间,所以可以直接输出1节点的信息
{
if(L<=l&&r<=R)
{
col[rt]=c;
sum[rt]=(r-l+1)*c;
return;
}
pushdown(rt,r-l+1);
int m=(l+r)/2;
if(L<=m) update(L,R,c,lson);
if(R>m) update(L,R,c,rson);
pushUP(rt);
}
int main()
{
int T,n,m;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++)
{
scanf("%d%d",&n,&m);
build(1,n,1);;
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
update(a,b,c,1,n,1);
}
printf("Case %d: The total value of the hook is %d.\n",cas , sum[1]);
}
return 0;
}</span>

poj 3468

链接:http://poj.org/problem?id=3468

题解:很好的一个区间更新的线段树的模型,线段树的功能,update成段增减,query区间求和,关键在于对pushdown的理解,当扩展区间与节点上区间完全吻合时,停止向下

#include<iostream>
#include<cstdio>
#include<cstring>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn=100001;
long long sum[maxn<<2],col[maxn<<2];
void pushUP(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int m)
{
if(col[rt])
{
col[rt<<1]+=col[rt];
col[rt<<1|1]+=col[rt];
sum[rt<<1]+=(m-(m>>1))*col[rt];
sum[rt<<1|1]+=(m>>1)*col[rt];
col[rt]=0;
}
}
void build(int l,int r,int rt)
{
col[rt]=0;
if(l==r)
{
scanf("%lld",&sum[rt]);
return;
}
int m=(l+r)/2;
build(lson);
build(rson);
pushUP(rt);
}
void update(int L,int R,int c,int l,int r,int rt) //成段增减
{
if(L<=l&&r<=R)
{
col[rt]+=c;
sum[rt]+=c*(r-l+1);
return;
}
pushdown(rt,r-l+1);
int m=(l+r)/2;
if(L<=m) update(L,R,c,lson);
if(R>m) update(L,R,c,rson);
pushUP(rt);
}
long long query(int L,int R,int l,int r,int rt) //区间求和
{
if(L<=l&&r<=R)
return sum[rt];
pushdown(rt,r-l+1);
long long ret=0;
int m=(l+r)/2;
if(L<=m) ret+=query(L,R,lson);
if(R>m) ret+=query(L,R,rson);
return ret;
}
int main()
{
int n,q;
scanf("%d%d",&n,&q);
build(1,n,1);
while(q--)
{
int a,b,c;
char op[2];
scanf("%s",op);
if(op[0]=='Q')
{
scanf("%d%d",&a,&b);
printf("%lld\n",query(a,b,1,n,1));
}
else
{
scanf("%d%d%d",&a,&b,&c);
update(a,b,c,1,n,1);
}
}
return 0;
}

poj2528(线段树+离散化)

题目链接:http://poj.org/problem?id=2528

题目解答:

离散化就是压缩区间,使原有的长区间映射到新的短区间,但是区间压缩前后的覆盖关系不变。举个例子:

有一条1到10的数轴(长度为9),给定4个区间[2,4] [3,6] [8,10] [6,9],覆盖关系就是后者覆盖前者,每个区间染色依次为 1 2 3 4。

现在我们抽取这4个区间的8个端点,2 4 3 6 8 10 6 9

然后删除相同的端点,这里相同的端点为6,则剩下2 4 3 6 8 10 9

对其升序排序,得2 3 4 6 8 9 10

然后建立映射

2     3     4     6     8     9   10

↓     ↓      ↓     ↓     ↓     ↓     ↓

1     2     3     4     5     6     7

那么新的4个区间为 [1,3] [2,4] [5,7] [4,6],覆盖关系没有被改变。新数轴为1到7,即原数轴的长度从9压缩到6,显然构造[1,7]的线段树比构造[1,10]的线段树更省空间,搜索也更快,但是求解的结果却是一致的。

离散化时有一点必须要注意的,就是必须先剔除相同端点后再排序,这样可以减少参与排序元素的个数,节省时间。

由于此题数据较大,所以此题要用离散化

线段树功能:update:成段替换 query:简单hash

#include<iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 11111;
bool hash[maxn];
int li[maxn] , ri[maxn];
int X[maxn*3];
int col[maxn<<4];
int cnt;
void PushDown(int rt) //更新到儿子节点(此处为覆盖,所以用这种方法更新)
{
if (col[rt] != -1)
{
col[rt<<1] = col[rt<<1|1] = col[rt];
col[rt] = -1;
}
}
void update(int L,int R,int c,int l,int r,int rt) //成段替换
{
if (L <= l && r <= R) {
col[rt] = c;
return ;
}
PushDown(rt);
int m = (l + r) >> 1;
if (L <= m) update(L , R , c , lson);
if (m < R) update(L , R , c , rson);
}
void query(int l,int r,int rt) //简单的hash,cnt统计离散化以后的长度
{
if (col[rt] != -1)
{
if (!hash[col[rt]]) cnt ++;
hash[ col[rt] ] = true;
return ;
}
if (l == r) return ;
int m = (l + r) >> 1;
query(lson);
query(rson);
}
int Bin(int key,int n,int X[]) //二分查找的过程
{
int l = 0 , r = n - 1;
while (l <= r)
{
int m = (l + r) >> 1;
if (X[m] == key) return m;
if (X[m] < key) l = m + 1;
else r = m - 1;
}
return -1;
}
int main()
{
int T , n;
scanf("%d",&T);
while (T --)
{
scanf("%d",&n);
int nn = 0;
for (int i = 0 ; i < n ; i ++) //离散化的过程
{
scanf("%d%d",&li[i] , &ri[i]);
X[nn++] = li[i];
X[nn++] = ri[i];
}
sort(X , X + nn);
int m = 1;
for (int i = 1 ; i < nn; i ++)
{
if (X[i] != X[i-1]) X[m ++] = X[i];
}
for (int i = m - 1 ; i > 0 ; i --)
{
if (X[i] != X[i-1] + 1) X[m ++] = X[i-1] + 1;
}
sort(X , X + m);
memset(col , -1 , sizeof(col));
for (int i = 0 ; i < n ; i ++)
{
int l = Bin(li[i], m, X);
int r = Bin(ri[i], m, X);
update(l, r, i, 0, m - 1, 1);
}
cnt = 0;
memset(hash, false, sizeof(hash));
query(0, m - 1, 1);
printf("%d\n",cnt);
}
return 0;
}

线段树之成段更新( 需要用到延迟标记,简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候)的更多相关文章

  1. Codeforces295A - Greg and Array(线段树的成段更新)

    题目大意 给定一个序列a[1],a[2]--a[n] 接下来给出m种操作,每种操作是以下形式的: l r d 表示把区间[l,r]内的每一个数都加上一个值d 之后有k个操作,每个操作是以下形式的: x ...

  2. hdu 1698 Just a Hook(线段树之 成段更新)

    Just a Hook                                                                             Time Limit: ...

  3. hdu 4614 Vases and Flowers(线段树:成段更新)

    线段树裸题.自己写复杂了,准确说是没想清楚就敲了. 先是建点为已插花之和,其实和未插花是一个道理,可是开始是小绕,后来滚雪球了,跪了. 重新建图,分解询问1为:找出真正插画的开始点和终止点,做成段更新 ...

  4. POJ 2777 Count Color(线段树之成段更新)

    Count Color Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 33311 Accepted: 10058 Descrip ...

  5. POJ3648 A Simple Problem with Integers(线段树之成段更新。入门题)

    A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 53169 Acc ...

  6. hdu1698 Just a Hook 线段树:成段替换,总区间求和

    转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1698 Problem ...

  7. hdu 1698 线段树(成段替换 区间求和)

    一条钩子由许多小钩子组成 更新一段小钩子 变成铜银金 价值分别变成1 2 3 输出最后的总价值 Sample Input11021 5 25 9 3 Sample OutputCase 1: The ...

  8. POJ 3468 A Simple Problem with Integers //线段树的成段更新

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 59046   ...

  9. poj2528 Mayor's posters(线段树之成段更新)

    Mayor's posters Time Limit: 1000MSMemory Limit: 65536K Total Submissions: 37346Accepted: 10864 Descr ...

随机推荐

  1. 将数字转换成Excel表头格式的字母序号

    /**     * 从0开始算起,0-25转A-Z     * @param num     * @return  Character.valueOf((char)((num-1)+65))+&quo ...

  2. nyoj_90_整数划分_201403161553

    整数划分 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 将正整数n表示成一系列正整数之和:n=n1+n2+…+nk, 其中n1≥n2≥…≥nk≥1,k≥1. 正整数 ...

  3. 学习技术的三部曲:WHAT、HOW、WHY

    ★第一步:WHAT 所谓的“WHAT”也就是“What is it?”——这是最简单的层次.在这个层次,你要搞清楚某个东东是[什么]样子的?有[什么]用处?有[什么]特性?有[什么]语法?...... ...

  4. Paul Graham:梦寐以求的编程语言

    我的朋友曾对一位著名的操作系统专家说他想要设计一种真正优秀的编程语言.那位专家回答,这是浪费时间,优秀的语言不一定会被市场接受,很可能无人使用,因为语言的流行不取决于它本身.至少,那位专家设计的语言就 ...

  5. 服务器Out of Memory

    之前有次把图片存储在数据库,结果读取时候报错了:Out of Memory.. 图片本来不应该存储在数据库中的,消耗内存太大,既然已经这样,那就先解决问题,不改存储方式. 如果一个应用程序为了提高性能 ...

  6. Docker资源限制实现——cgroup

    摘要 随着Docker技术被越来越多的个人.企业所接受,其用途也越来越广泛.Docker资源管理包含对CPU.内存.IO等资源的限制,但大部分Docker使用者在使用资源管理接口时往往还比较模糊. 本 ...

  7. BUPT 2012复试机考 2T

    题目描述 ​给你一个n*n的矩阵, , 求其矩阵的k次幂,即Pk 输入格式 第一行,一个整数T(0<T<=10),表示要求矩阵的个数. 接下来有T组数据,每组数据格式如下: 第一行:两个数 ...

  8. underscore.js 页面数据渲染

    1.underscore.js  源码 // Underscore.js 1.8.3 // http://underscorejs.org // (c) 2009-2015 Jeremy Ashken ...

  9. HBuilder开发App教程06-首页

    实战 前面几节基本是一些概念的普及, 正如前面提到的,本教程会以滴石作为范例进行解说, 有兴趣的能够先行下载体验一下.或者下载源代码研究下. 新建项目 打开HBuilder,在项目管理器中右键--新建 ...

  10. 获取Wifi密码,不知道是不是真的

    package com.example.wifipassword; import java.util.List; import android.app.Activity; import android ...