HDU - 6521 Party (SYSU校赛K题)(线段树)
题意:n个人排成一列,一开始他们互不认识,每次选[l,r]上的人开party,使他们互相认识,求出每次party之后新互相认识的人的对数。
思路:把“互相认识”变成单向连边,只考虑左边的人对右边的贡献。对于每个人,他认识的人的区间必然是连续的,可以维护他认识的最右边的人R,这样更新操作相当于把[l,r]所有人的R值变成max(R,r),可以构造线段树维护每个区间中R的最小值mi,如果最小值大于等于R的话就不用更新了,直接退出,否则暴力修改每个点的值。
先上个假算法:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+,inf=0x3f3f3f3f;
#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((l+r)>>1)
int mi[N<<],n,m;
ll ans;
void pu(int u) {mi[u]=min(mi[ls],mi[rs]);}
void build(int u=,int l=,int r=n) {
if(l==r) {mi[u]=l; return;}
build(ls,l,mid),build(rs,mid+,r),pu(u);
}
void upd(int L,int R,int u=,int l=,int r=n) {
if(l>R||r<L||mi[u]>=R)return;
if(l==r) {ans+=R-mi[u],mi[u]=R; return;}
upd(L,R,ls,l,mid),upd(L,R,rs,mid+,r),pu(u);
}
int main() {
while(scanf("%d%d",&n,&m)==) {
build();
while(m--) {
ans=;
int l,r;
scanf("%d%d",&l,&r);
upd(l,r);
printf("%lld\n",ans);
}
}
return ;
}
这个算法本身是没有问题的,交上去也能AC,但会被一些极端的数据卡死,比如[1,1],[1,2],...,[1,n]这样的,会被卡成n^2,因此可以加一些优化。
由于每个人认识的最右边的人R的值是非递减的,即任意i>j,R[i]>=R[j],因此每次发生变化的区间必然是连续的,可以把单点修改换成区间修改,这样就不会被卡了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+,inf=0x3f3f3f3f;
#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((l+r)>>1)
int mx[N<<],mi[N<<],lz[N<<],n,m;
ll sum[N<<],ans;
void pu(int u) {
mi[u]=min(mi[ls],mi[rs]);
mx[u]=max(mx[ls],mx[rs]);
sum[u]=sum[ls]+sum[rs];
}
void pd(int u,int l,int r) {
if(lz[u]) {
sum[ls]=(ll)lz[u]*(mid-l+),sum[rs]=(ll)lz[u]*(r-mid);
mi[ls]=mi[rs]=mx[ls]=mx[rs]=lz[ls]=lz[rs]=lz[u],lz[u]=;
}
}
void build(int u=,int l=,int r=n) {
lz[u]=;
if(l==r) {sum[u]=mi[u]=mx[u]=l; return;}
build(ls,l,mid),build(rs,mid+,r),pu(u);
}
void upd(int L,int R,int u=,int l=,int r=n) {
if(l>R||r<L||mi[u]>=R)return;
if(l>=L&&r<=R&&mx[u]<=R) {sum[u]=(ll)R*(r-l+),mi[u]=mx[u]=lz[u]=R; return;}
pd(u,l,r);
upd(L,R,ls,l,mid),upd(L,R,rs,mid+,r),pu(u);
}
int main() {
while(scanf("%d%d",&n,&m)==) {
build(),ans=sum[];
while(m--) {
int l,r;
scanf("%d%d",&l,&r);
upd(l,r);
printf("%lld\n",sum[]-ans);
ans=sum[];
}
}
return ;
}
然后据说还有一种叫“吉司机线段树”的东西也能做?赶紧学了学(便乘),感觉对于区间取max/min这类问题的处理强大的,普适性也比较高。
对于区间取max操作,其基本思想是维护区间和sum,区间最小值mi,区间次小值se以及区间最小值个数nmi。如果要对[l,r]上的所有数与x取max,那么分三种情况讨论即可:
1)若x<=mi,则修改操作无效,退出
2)若mi<x<se,则将mi改成x,(sum+=x-mi)*ni,其余不变,同时下放标记
3)若x>=se,则在左右区间递归进行下去
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+,inf=0x3f3f3f3f;
#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((l+r)>>1)
int mi[N<<],nmi[N<<],se[N<<],lz[N<<],n,m;
ll sum[N<<],ans;
void pu(int u) {
sum[u]=sum[ls]+sum[rs];
mi[u]=min(mi[ls],mi[rs]),se[u]=max(mi[ls],mi[rs]);
se[u]=se[u]==mi[u]?min(se[ls],se[rs]):min(se[u],min(se[ls],se[rs]));
nmi[u]=(mi[ls]==mi[u]?nmi[ls]:)+(mi[rs]==mi[u]?nmi[rs]:);
}
void change(int u,int x) {sum[u]+=(ll)nmi[u]*(x-mi[u]),mi[u]=lz[u]=x;}
void pd(int u) {
if(~lz[u]) {
if(mi[ls]<lz[u])change(ls,lz[u]);
if(mi[rs]<lz[u])change(rs,lz[u]);
lz[u]=-;
}
}
void build(int u=,int l=,int r=n) {
lz[u]=-;
if(l==r) {sum[u]=mi[u]=l,nmi[u]=,se[u]=inf; return;}
build(ls,l,mid),build(rs,mid+,r),pu(u);
}
void upd(int L,int R,int x,int u=,int l=,int r=n) {
if(l>R||r<L||x<=mi[u])return;
if(l>=L&&r<=R&&x<se[u]) {change(u,x); return;}
pd(u),upd(L,R,x,ls,l,mid),upd(L,R,x,rs,mid+,r),pu(u);
}
int main() {
while(scanf("%d%d",&n,&m)==) {
build(),ans=sum[];
while(m--) {
int l,r;
scanf("%d%d",&l,&r);
upd(l,r,r);
printf("%lld\n",sum[]-ans);
ans=sum[];
}
}
return ;
}
HDU - 6521 Party (SYSU校赛K题)(线段树)的更多相关文章
- HDU - 6513 Reverse It (SYSU校赛C题)(组合数学+容斥)
题目链接 题意:给定一个n*m的矩阵,可以选择至多两个子矩阵将其反转,求能形成多少种不同的矩阵. 任选一个矩阵有$C_{n+1}^{2}C_{m+1}^{2}$种方法,任选两个不同的矩阵有$C_{C_ ...
- hdu 4031 2011成都赛区网络赛A题 线段树 ***
就是不知道时间该怎么处理,想了好久,看了别人的题解发现原来是暴力,暴力也很巧妙啊,想不出来的那种 -_-! #include<cstdio> #include<iostream&g ...
- hdu 5475 模拟计算器乘除 (2015上海网赛H题 线段树)
给出有多少次操作 和MOD 初始值为1 操作1 y 表示乘上y操作2 y 表示除以第 y次操作乘的那个数 线段树的叶子结点i 表示 第i次操作乘的数 将1替换成y遇到操作2 就把第i个结点的值 替换成 ...
- NOJ/HUST 1095 校赛 Just Go 线段树模板题
Description There is a river, which contains n stones from left to right. These stones are magic, ea ...
- ZOJ 3949 (17th 浙大校赛 B题,树型DP)
题目链接 The 17th Zhejiang University Programming Contest Problem B 题意 给定一棵树,现在要加一条连接$1$(根结点)和$x$的边,求加 ...
- UVAlive7141 BombX 14年上海区域赛D题 线段树+离散化
题意:一个无限大的棋盘, 有n个小兵, 给出了n个兵的坐标, 现在有一个长为width 高为height的炸弹放在棋盘上, 炸弹只能上下左右平移, 不能旋转. 且放炸弹的区域不能含有士兵, 炸弹可以一 ...
- hdu 5266 pog loves szh III(lca + 线段树)
I - pog loves szh III Time Limit:6000MS Memory Limit:131072KB 64bit IO Format:%I64d & %I ...
- HDU 2795 Billboard(宣传栏贴公告,线段树应用)
HDU 2795 Billboard(宣传栏贴公告,线段树应用) ACM 题目地址:HDU 2795 Billboard 题意: 要在h*w宣传栏上贴公告,每条公告的高度都是为1的,并且每条公告都要 ...
- 「CQOI2006」简单题 线段树
「CQOI2006」简单题 线段树 水.区间修改,单点查询.用线段树维护区间\([L,R]\)内的所有\(1\)的个数,懒标记表示为当前区间是否需要反转(相对于区间当前状态),下方标记时懒标记取反即可 ...
随机推荐
- MCM写作
MCM 写作 引言的写作 对赛题的解读. 对现有研究成果的松树与评论 对解题思路和主要方法进行简介 引言第一句话是最重要的,应该激发读者阅读兴趣,应该浅显易懂,不用或者少用数学公式 赛题选定以后要首先 ...
- ABP 源码分析汇总之 AutoMapper
AutoMapper 是一个对象映射工具, 安装时只需要安装 如下即可: 有关于它的介绍,参考官网:http://automapper.org/ AutoMapper使用比较简单,还是直奔主题,看一下 ...
- codeforces796E Exam Cheating
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- git rm -r --cache命令 及 git .gitignore 文件
git 的 .gitignore 文件的作用是在代码提交时自动忽略一个文件.不将其纳入版本控制系统. 比如.一般我们会忽略IDE自动生成的配置文件等. 如果一个你要忽略的文件已经纳入到了git ,也 ...
- 使用HandleErrorAttribute处理异常
ASP.NET MVC 默认提供了一个异常过滤器HandleError特性,使用该特性可以极为方便的捕捉并处理控制器和操作抛出的异常,也可以将此特性注册为全局异常过滤器从而捕捉项目中的所有异常.如果想 ...
- Dubbo通过注解实现RPC调用
启动Dubbo服务有2个方式,1是通过xml配置,2是通过注解来实现,这点和Spring相似. 采用XML配置如下: <?xml version="1.0" encodin ...
- BZOJ 1010 [HNOI2008]玩具装箱 (斜率优化DP)
题目链接 http://www.lydsy.com/JudgeOnline/problem.php?id=1010 思路 [斜率优化DP] 我们知道,有些DP方程可以转化成DP[i]=f[j]+x[i ...
- Oracle 反应太后知后觉了.
很久已经提过一个SR,关于BES一个用户可以用两个密码登陆EBS系统的问题,但是SR解决太慢,而且一致强调你们的版本太低,需要升级到最新的版本,考虑客户化的问题,我们的版本没有升级(R2.1.1),无 ...
- redisAPI整理
全局命令 1.查看所有键 keys * 2.键总数 dbsize 3.检查键是否存在 exists key 4.删除键 del key del key1 key2 key3 5.键过期 expire ...
- kvm虚拟主机安装速度很慢
在c6220 II上部署虚拟化遇到的问题: 1.部署完kvm后,安装虚拟主机的过程非常缓慢,但是最终能成功 原因:宿主机BIOS的virtualization technology设置为Disable ...