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. codevs——1570 去看电影

    1570 去看电影  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description 农夫约翰带着他的一些奶牛去看电影.而他的 ...

  2. Scrum软件开发

    Scrum 什么是Scrum Scrum是迭代式增量软件开发过程,通常用于敏捷软件开发.Scrum包括了一系列实践和预定义角色的过程骨架.Scrum中的主要角色包括同项目经理类似的Scrum主管角色负 ...

  3. Java代码规范和质量检查插件-Checkstyle(官方资源)

    其实Checkstyle是一个JAR包,然后第三方开发者开发了Eclipse/IDEA的插件. 官网: https://github.com/checkstyle/checkstyle Eclipse ...

  4. 【Java TCP/IP Socket】基于线程池的TCP服务器(含代码)

    了解线程池 在http://blog.csdn.net/ns_code/article/details/14105457(读书笔记一:TCP Socket)这篇博文中,服务器端采用的实现方式是:一个客 ...

  5. pandas入门指南

    上一篇讲了numpy,除此之外,还有一个工具我们一定会使用,那就是pandas.如果说numpy中数据存储形式是列表的话,那么pandas中数据的存储形式更像是字典.为什么这么说呢?因为pandas中 ...

  6. 转: NetBean远程开发的格式与过程

    1. 介绍远程3种模式 https://netbeans.org/kb/docs/cnd/remote-modes.html 评注:英文的,3种模式讲的非常到位.服务器开发还是全远程比较不错.

  7. mysqldbcopy 数据库复制工具

    命令参考 mysqldbcopy --source=root:'xxxxxxx'@database s --destination=root:'^%xxxxxz'@databases orange:o ...

  8. Our happy ending

    题目链接 题意: 输入n.k.L,n个数,最大值不超过L,在序列中取若干个数和能达到k的序列个数 n,k<=20 , 0<=L<=10^9 分析: 题目关键在于和k比較小,所以能够考 ...

  9. ng-options bug解决方案(示例)

    情况: 无法获取 ng-model 的值 解决方案: 绑定到对象的属性值上 1.页面 <ion-view hide-nav-bar="true"> <ion-co ...

  10. 走入asp.net mvc不归路:[5]Action的返回

    asp.net mvc提供了多种返回方式,一方面使得视图可以重用,另一方面灵活强大,有直接返回视图,返回Json,返回文件流,返回到相同Controller的Action,返回到另一个Controll ...