Tunnel Warfare 线段树 区间合并|最大最小值
B - Tunnel WarfareHDU - 1540
这个有两种方法,一个是区间和并,这个我个人感觉异常恶心
第二种方法就是找最大最小值 kuangbin——线段树专题 H - Tunnel Warfare <-- 这个博客讲的很清楚
#include <cstdio>//法一:最大值最小值法,这个就是每一个点,如果这个点没有被摧毁,那就找到这个点最左边的和最右边的
#include <cstdlib>//最大-最小+1.这个就是这个最大连续长度。
#include <queue>//建树,很简单,主要就是query和update。
#include <algorithm>//这个地方的怎么去找一个包含一个数的一个区间的最大最小值呢?
#include <vector>//这个就是从上面往下面查询的过程中,就去找,如果是找最大值就去max,最小值就取min
#include <cstring>//这个要注意建树,这个区间的最大值的意思是,小于等于这个数的最大的被炸了的村庄,这个就说明,开始最大值为0,因为没有任何一个村庄被炸
#include <string>//区间的最小值,意思是大于等于这个数,被炸了的村庄的最小值,开始为n+1.因为没有村庄被炸。
#include <iostream>
#include <stack>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + ;
struct node
{
int l, r;
int mx, mn;
}tree[maxn*];
int n;
void build(int id,int l,int r)
{
tree[id].l = l;
tree[id].r = r;
if(l==r)
{
tree[id].mn = n+;
tree[id].mx = ;
return;
}
int mid = (l + r) >> ;
build(id << , l, mid);
build(id << | , mid + , r);
tree[id].mx = max(tree[id << ].mx, tree[id << | ].mx);
tree[id].mn = min(tree[id << ].mn, tree[id << | ].mn);
} void update_max(int id,int x,int z)
{
if(tree[id].l==tree[id].r)
{
tree[id].mx = z;
return;
}
int mid = (tree[id].l + tree[id].r) >> ;
if(x<=mid) update_max(id << , x, z);
if (x > mid) update_max(id << | , x, z);
tree[id].mx = max(tree[id << ].mx, tree[id << | ].mx);
} void update_min(int id,int x,int z)
{
if(tree[id].l==tree[id].r)
{
tree[id].mn = z;
return;
}
int mid = (tree[id].l + tree[id].r) >> ;
if (x <= mid) update_min(id << , x, z);
if (x > mid) update_min(id << | , x, z);
tree[id].mn = min(tree[id << ].mn, tree[id << | ].mn);
} int query_max(int id,int x,int y)
{
int ans = ;
if(x<=tree[id].l&&y>=tree[id].r)
{
return tree[id].mx;
}
int mid = (tree[id].l + tree[id].r) >> ;
if (x <= mid) ans = max(ans, query_max(id << , x, y));
if (y > mid) ans = max(ans, query_max(id << | , x, y));
return ans;
} int query_min(int id,int x,int y)
{
int ans = inf;
if(x<=tree[id].l&&y>=tree[id].r)
{
return tree[id].mn;
}
int mid = (tree[id].l + tree[id].r) >> ;
if (x <= mid) ans = min(ans, query_min(id << , x, y));
if (y > mid) ans = min(ans, query_min(id << | , x, y));
return ans;
} int main()
{ int m, x;
while(cin >> n >> m)
{
stack<int>sta;
build(, , n);
while(m--)
{
char s[];
scanf("%s", s);
if(s[]=='D')
{
cin >> x;
update_max(, x, x);
update_min(, x, x);
sta.push(x);
}
if(s[]=='R')
{
int y = sta.top(); sta.pop();
update_max(, y, );
update_min(, y, n + );
}
if(s[]=='Q')
{
cin >> x;
int L = query_min(, x, n + );
int R = query_max(, , x);
//printf("%d %d\n", L, R);
if (L == R) printf("0\n");
else printf("%d\n", L - R - );
}
}
} return ;
}
方法一
//法二:区间合并,这个应该更好懂一点,就是维护一下一个区间的前缀后缀长度
//这个更新应该比较简单,
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <iostream>
#include <stack>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + ;
struct node
{
int l, r, len;
int max_pre, max_last;
}tree[maxn*]; void push_up(int id)
{
tree[id].max_pre = tree[id << ].max_pre;
tree[id].max_last = tree[id << | ].max_last;
if (tree[id << ].max_pre == tree[id << ].len)
{
tree[id].max_pre += tree[id << | ].max_pre;
}
if(tree[id<<|].max_last==tree[id<<|].len)
{
tree[id].max_last += tree[id << ].max_last;
}
} void build(int id,int l,int r)
{
tree[id].l = l;
tree[id].r = r;
tree[id].len = r - l + ;
if(l==r)
{
tree[id].max_pre = tree[id].max_last = ;
return;
}
int mid = (l + r) >> ;
build(id << , l, mid);
build(id << | , mid + , r);
push_up(id);
} void update(int id,int x,int z)
{
if(tree[id].l==tree[id].r)
{
tree[id].max_pre = z;
tree[id].max_last = z;
return;
}
int mid = (tree[id].l + tree[id].r) >> ;
if (x <= mid) update(id << , x, z);
else update(id << | , x, z);
push_up(id);
} int query_pre(int id,int x,int y)
{
int ans = , res = ;
if(x<=tree[id].l&&y>=tree[id].r)
{
//printf("tree[%d].max_pre=%d\n", id, tree[id].max_pre);
return tree[id].max_pre;
}
//printf("id=%d x=%d y=%d\n", id, x, y);
int mid = (tree[id].l + tree[id].r) >> ;
if (x <= mid) ans=query_pre(id << , x, y);
if (y > mid) res=query_pre(id << | , x, y);
//printf("id=%d ans=%d res=%d mid=%d\n",id, ans, res,mid);
if (ans >= mid - x + )
{
//printf("tree[%d].max_pre=%d mid=%d x=%d\n",id, tree[id].max_pre, mid, x);
ans += res;
}
return ans;
} int query_last(int id,int x,int y)
{
int ans = , res = ;
if (x <= tree[id].l&&y >= tree[id].r)
{
//printf("tree[%d].last=%d\n", id, tree[id].max_last);
return tree[id].max_last;
}
//printf("id=%d x=%d y=%d\n", id, x, y);
int mid = (tree[id].l + tree[id].r) >> ;
if (x <= mid) ans = query_last(id << , x, y);
if (y > mid) res = query_last(id << | , x, y);
//printf("id=%d mid=%d ans=%d res=%d\n", id, mid,ans, res);
if (res >= y-mid)
{
//printf("tree[%d].max_last=%d mid=%d x=%d\n",id,tree[id].max_last, mid, x);
res += ans;
}
return res;
} int main()
{
int n, m;
while(scanf("%d %d",&n,&m)!=EOF)
{
stack<int>sta;
build(, , n);
while(m--)
{
char s[];
scanf("%s", s);
if(s[]=='D')
{
int x;
cin >> x;
update(, x, );
sta.push(x);
}
if(s[]=='R')
{
int y = sta.top(); sta.pop();
update(, y, );
}
if(s[]=='Q')
{
int x;
cin >> x;
int ans = query_pre(, x, n);
ans += query_last(, , x);
if(ans) printf("%d\n", ans-);
else printf("0\n");
}
}
}
return ;
}
/*
7 10
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4
Q 3
*/
方法二
Tunnel Warfare 线段树 区间合并|最大最小值的更多相关文章
- HDU 1540 Tunnel Warfare 线段树区间合并
Tunnel Warfare 题意:D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少 思路:一个节点的最大连续区间由(左儿子的最大的连续区间,右儿子的最大连续区 ...
- HDU1540 Tunnel Warfare —— 线段树 区间合并
题目链接:https://vjudge.net/problem/HDU-1540 uring the War of Resistance Against Japan, tunnel warfare w ...
- hdu 1540 Tunnel Warfare 线段树 区间合并
题意: 三个操作符 D x:摧毁第x个隧道 R x:修复上一个被摧毁的隧道,将摧毁的隧道入栈,修复就出栈 Q x:查询x所在的最长未摧毁隧道的区间长度. 1.如果当前区间全是未摧毁隧道,返回长度 2. ...
- Tunnel Warfare HDU 1540 区间合并+最大最小值
Tunnel Warfare HDU 1540 区间合并+最大最小值 题意 D x是破坏这个点,Q x是表示查询以x所在的最长的连续的点的个数,R是恢复上一次破坏的点. 题解思路 参考的大佬博客 这里 ...
- hdu 1540 Tunnel Warfare(线段树区间统计)
Tunnel Warfare Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) T ...
- Tunnel Warfare(HDU1540+线段树+区间合并)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1540 题目: 题意:总共有n个村庄,有q次操作,每次操作分为摧毁一座村庄,修复一座村庄,和查询与询问的 ...
- 线段树区间合并优化dp——cf1197E(好)
线段树优化dp的常见套路题,就是先按某个参数排序,然后按这个下标建立线段树,再去优化dp 本题由于要维护两个数据:最小值和对应的方案数,所以用线段树区间合并 /* dp[i]表示第i个套娃作为最内层的 ...
- POJ 3667 Hotel(线段树 区间合并)
Hotel 转载自:http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html [题目链接]Hotel [题目类型]线段树 ...
- HDU 3911 线段树区间合并、异或取反操作
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3911 线段树区间合并的题目,解释一下代码中声明数组的作用: m1是区间内连续1的最长长度,m0是区间内连续 ...
随机推荐
- iNeuOS工业互联平台,部署在智能硬件网关,实现了从边缘端到云端的一体化部署
目 录 1. 概述... 2 2. 平台演示... 3 3. 智能硬件网关配置(参考)... 3 4. iNeuOS在网关中的部署步骤... 5 4 ...
- python填写金数据
''' 将 main 中的{url}改为真 url 将 setd_data中 {姓名} {纬度} {经度} {地址} 改为确切数据 数据自行参考post 结果判断基于响应中是否包含“谢谢参与”字样 ' ...
- SaaS、PaaS、IaaS的含义与区别
先上个图,直观的了解一下 云计算有SPI,即SaaS.PaaS和IaaS三大服务模式. PaaS和IaaS源于SaaS SaaS Software as a Service 软件即服务,提供给客户的服 ...
- 植物大战僵尸的代码如何使用python来实现
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:程序IT圈 PS:如有需要Python学习资料的小伙伴可以加点击下方链 ...
- 在vue中使用ztree树插件
插件资源及api:树官网 本事例是在vue3.0+中演示,事例是实际项目中正在用的组件所以部分打了马赛克. 1.插件准备(提前准备好插件文件) 可以直接在官网下载,搭建好脚手架后将准备好的文件放在li ...
- NIO教程 ——检视阅读
NIO教程 --检视阅读 参考 BIO,NIO,AIO 总结 Java NIO浅析 Java NIO 教程--极客,蓝本 Java NIO 系列教程 --并发编程网 BIO,NIO--知乎 NIO 入 ...
- 如何在非 sudo 用户下运行 docker 命令?
当我们在一台 Linux 系统中安装了 Docker 后, 有时候会遇到下面这样的错误, 我们在运行 docker 的命令时必须加上 sudo, 例如: sudo docker ps, 但是我们其实更 ...
- 常问的MySQL面试题整理
char.varchar 的区别是什么? varchar是变长而char的长度是固定的.如果创建的列是固定大小的,你会得到更好的性能 truncate 和 delete 的区别是什么? delete ...
- SpringCloud-Config 配置中心
概述 分布式系统面临的问题 微服务意味着要将单体应用中的业务拆分成一个个的子服务,这些服务都需要必要的配置信息才能运行,如果有上百个微服务,上百个配置文件,管理起来是非常困难的,这时候,一套集中式的. ...
- 从源码解读Spring如何解决bean循环依赖
1 什么是bean的循环依赖 循环依赖的原文是circular reference,指多个对象相互引用,形成一个闭环. 以两个对象的循环依赖为例: Spring中的循环依赖有 3 种情况: 构造器(c ...