题目链接

题意:n个人排成一列,一开始他们互不认识,每次选[l,r]上的人开party,使他们互相认识,求出每次party之后新互相认识的人的对数。

思路:把“互相认识”变成单向连边,只考虑左边的人对右边的贡献。对于每个人,他认识的人的区间必然是连续的,可以维护他认识的最右边的人R,这样更新操作相当于把[l,r]所有人的R值变成max(R,r),可以构造线段树维护每个区间中R的最小值mi,如果最小值大于等于R的话就不用更新了,直接退出,否则暴力修改每个点的值。

先上个假算法:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int N=5e5+,inf=0x3f3f3f3f;
  5. #define ls (u<<1)
  6. #define rs (u<<1|1)
  7. #define mid ((l+r)>>1)
  8. int mi[N<<],n,m;
  9. ll ans;
  10. void pu(int u) {mi[u]=min(mi[ls],mi[rs]);}
  11. void build(int u=,int l=,int r=n) {
  12. if(l==r) {mi[u]=l; return;}
  13. build(ls,l,mid),build(rs,mid+,r),pu(u);
  14. }
  15. void upd(int L,int R,int u=,int l=,int r=n) {
  16. if(l>R||r<L||mi[u]>=R)return;
  17. if(l==r) {ans+=R-mi[u],mi[u]=R; return;}
  18. upd(L,R,ls,l,mid),upd(L,R,rs,mid+,r),pu(u);
  19. }
  20. int main() {
  21. while(scanf("%d%d",&n,&m)==) {
  22. build();
  23. while(m--) {
  24. ans=;
  25. int l,r;
  26. scanf("%d%d",&l,&r);
  27. upd(l,r);
  28. printf("%lld\n",ans);
  29. }
  30. }
  31. return ;
  32. }

这个算法本身是没有问题的,交上去也能AC,但会被一些极端的数据卡死,比如[1,1],[1,2],...,[1,n]这样的,会被卡成n^2,因此可以加一些优化。

由于每个人认识的最右边的人R的值是非递减的,即任意i>j,R[i]>=R[j],因此每次发生变化的区间必然是连续的,可以把单点修改换成区间修改,这样就不会被卡了。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int N=5e5+,inf=0x3f3f3f3f;
  5. #define ls (u<<1)
  6. #define rs (u<<1|1)
  7. #define mid ((l+r)>>1)
  8. int mx[N<<],mi[N<<],lz[N<<],n,m;
  9. ll sum[N<<],ans;
  10. void pu(int u) {
  11. mi[u]=min(mi[ls],mi[rs]);
  12. mx[u]=max(mx[ls],mx[rs]);
  13. sum[u]=sum[ls]+sum[rs];
  14. }
  15. void pd(int u,int l,int r) {
  16. if(lz[u]) {
  17. sum[ls]=(ll)lz[u]*(mid-l+),sum[rs]=(ll)lz[u]*(r-mid);
  18. mi[ls]=mi[rs]=mx[ls]=mx[rs]=lz[ls]=lz[rs]=lz[u],lz[u]=;
  19. }
  20. }
  21. void build(int u=,int l=,int r=n) {
  22. lz[u]=;
  23. if(l==r) {sum[u]=mi[u]=mx[u]=l; return;}
  24. build(ls,l,mid),build(rs,mid+,r),pu(u);
  25. }
  26. void upd(int L,int R,int u=,int l=,int r=n) {
  27. if(l>R||r<L||mi[u]>=R)return;
  28. if(l>=L&&r<=R&&mx[u]<=R) {sum[u]=(ll)R*(r-l+),mi[u]=mx[u]=lz[u]=R; return;}
  29. pd(u,l,r);
  30. upd(L,R,ls,l,mid),upd(L,R,rs,mid+,r),pu(u);
  31. }
  32. int main() {
  33. while(scanf("%d%d",&n,&m)==) {
  34. build(),ans=sum[];
  35. while(m--) {
  36. int l,r;
  37. scanf("%d%d",&l,&r);
  38. upd(l,r);
  39. printf("%lld\n",sum[]-ans);
  40. ans=sum[];
  41. }
  42. }
  43. return ;
  44. }

然后据说还有一种叫“吉司机线段树”的东西也能做?赶紧学了学(便乘),感觉对于区间取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,则在左右区间递归进行下去

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int N=5e5+,inf=0x3f3f3f3f;
  5. #define ls (u<<1)
  6. #define rs (u<<1|1)
  7. #define mid ((l+r)>>1)
  8. int mi[N<<],nmi[N<<],se[N<<],lz[N<<],n,m;
  9. ll sum[N<<],ans;
  10. void pu(int u) {
  11. sum[u]=sum[ls]+sum[rs];
  12. mi[u]=min(mi[ls],mi[rs]),se[u]=max(mi[ls],mi[rs]);
  13. se[u]=se[u]==mi[u]?min(se[ls],se[rs]):min(se[u],min(se[ls],se[rs]));
  14. nmi[u]=(mi[ls]==mi[u]?nmi[ls]:)+(mi[rs]==mi[u]?nmi[rs]:);
  15. }
  16. void change(int u,int x) {sum[u]+=(ll)nmi[u]*(x-mi[u]),mi[u]=lz[u]=x;}
  17. void pd(int u) {
  18. if(~lz[u]) {
  19. if(mi[ls]<lz[u])change(ls,lz[u]);
  20. if(mi[rs]<lz[u])change(rs,lz[u]);
  21. lz[u]=-;
  22. }
  23. }
  24. void build(int u=,int l=,int r=n) {
  25. lz[u]=-;
  26. if(l==r) {sum[u]=mi[u]=l,nmi[u]=,se[u]=inf; return;}
  27. build(ls,l,mid),build(rs,mid+,r),pu(u);
  28. }
  29. void upd(int L,int R,int x,int u=,int l=,int r=n) {
  30. if(l>R||r<L||x<=mi[u])return;
  31. if(l>=L&&r<=R&&x<se[u]) {change(u,x); return;}
  32. pd(u),upd(L,R,x,ls,l,mid),upd(L,R,x,rs,mid+,r),pu(u);
  33. }
  34. int main() {
  35. while(scanf("%d%d",&n,&m)==) {
  36. build(),ans=sum[];
  37. while(m--) {
  38. int l,r;
  39. scanf("%d%d",&l,&r);
  40. upd(l,r,r);
  41. printf("%lld\n",sum[]-ans);
  42. ans=sum[];
  43. }
  44. }
  45. return ;
  46. }

HDU - 6521 Party (SYSU校赛K题)(线段树)的更多相关文章

  1. HDU - 6513 Reverse It (SYSU校赛C题)(组合数学+容斥)

    题目链接 题意:给定一个n*m的矩阵,可以选择至多两个子矩阵将其反转,求能形成多少种不同的矩阵. 任选一个矩阵有$C_{n+1}^{2}C_{m+1}^{2}$种方法,任选两个不同的矩阵有$C_{C_ ...

  2. hdu 4031 2011成都赛区网络赛A题 线段树 ***

    就是不知道时间该怎么处理,想了好久,看了别人的题解发现原来是暴力,暴力也很巧妙啊,想不出来的那种  -_-! #include<cstdio> #include<iostream&g ...

  3. hdu 5475 模拟计算器乘除 (2015上海网赛H题 线段树)

    给出有多少次操作 和MOD 初始值为1 操作1 y 表示乘上y操作2 y 表示除以第 y次操作乘的那个数 线段树的叶子结点i 表示 第i次操作乘的数 将1替换成y遇到操作2 就把第i个结点的值 替换成 ...

  4. NOJ/HUST 1095 校赛 Just Go 线段树模板题

    Description There is a river, which contains n stones from left to right. These stones are magic, ea ...

  5. ZOJ 3949 (17th 浙大校赛 B题,树型DP)

    题目链接  The 17th Zhejiang University Programming Contest Problem B 题意  给定一棵树,现在要加一条连接$1$(根结点)和$x$的边,求加 ...

  6. UVAlive7141 BombX 14年上海区域赛D题 线段树+离散化

    题意:一个无限大的棋盘, 有n个小兵, 给出了n个兵的坐标, 现在有一个长为width 高为height的炸弹放在棋盘上, 炸弹只能上下左右平移, 不能旋转. 且放炸弹的区域不能含有士兵, 炸弹可以一 ...

  7. hdu 5266 pog loves szh III(lca + 线段树)

    I - pog loves szh III Time Limit:6000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I ...

  8. HDU 2795 Billboard(宣传栏贴公告,线段树应用)

    HDU 2795 Billboard(宣传栏贴公告,线段树应用) ACM 题目地址:HDU 2795 Billboard 题意:  要在h*w宣传栏上贴公告,每条公告的高度都是为1的,并且每条公告都要 ...

  9. 「CQOI2006」简单题 线段树

    「CQOI2006」简单题 线段树 水.区间修改,单点查询.用线段树维护区间\([L,R]\)内的所有\(1\)的个数,懒标记表示为当前区间是否需要反转(相对于区间当前状态),下方标记时懒标记取反即可 ...

随机推荐

  1. 【网络结构】GoogLeNet inception-v1:Going deeper with convolutions论文笔记

    目录 0. 论文链接 1. 概述 2. inception 3. GoogleNet 参考链接 @ 0. 论文链接 1. 概述   GoogLeNet是谷歌团队提出的一种大体保持计算资源不变的前提下, ...

  2. codeforces776D The Door Problem

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  3. Linux安装keepalived

    1.下载安装ipvs安装包,进行解压 http://www.keepalived.org/software/ 2.创建安装路径连接 安装环境: yum -y install openssl-devel ...

  4. SQL Server 的索引结构实例

    目前SQL Server 的索引结构如下: 这个是聚集索引的存放形式: 非聚集索引的方式如下: 它们是以B+树的数据结构存放的. 相信大家都看过类似的图,但是没有直观的认识,下面举一个实际的例子来说明 ...

  5. 如何在 Ubuntu 中安装 QGit 客户端

    QGit是一款由Marco Costalba用Qt和C++写的开源的图形界面 Git 客户端.它是一款可以在图形界面环境下更好地提供浏览版本历史.查看提交记录和文件补丁的客户端.它利用git命令行来执 ...

  6. HDU 4099 大数+Trie

    Revenge of Fibonacci Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 204800/204800 K (Java/ ...

  7. Centos7 使用Dockerfile 制作自己的Dotnetcore程序镜像

    准备Centos7环境及Docker环境 从Docker hub拉取 Microsoft/dotnet 基础镜像(可以使用国内加速) 向Centos7指定目录上传Dotnet Core程序,目录: / ...

  8. Using Oracle Database In-Memory with Oracle E-Business Suite

    Database In-Memory is one of a number of options that can be deployed to address Oracle E-Business S ...

  9. DataTable RowFilter 过滤数据

    用Rowfilter加入过滤条件 eg: string sql = "select Name,Age,Sex from UserInfo"; DataTable dt = Data ...

  10. C++复习10.对象的初始化拷贝析构函数

    对象的初始化.拷贝构造和析构函数 20131002 构造函数.析构函数.赋值函数是类的基本函数.每一个类只有一个析构函数,但是可以有多个构造函数.多个赋值函数.一般如果类中没有显示的声明和定义上述函数 ...