相当于将线段划分成两个集合使集合内线段不相交,并且可以发现线段相交等价于逆序对。也即要将原序列划分成两个单增序列。由dilworth定理,如果存在长度>=3的单减子序列,无解,可以先判掉。

  这个时候有两种显然的暴力。

  将点集划分成两部分使内部无边显然就是二分图,于是第一种暴力是在逆序对之间连边,答案即为2连通块个数,因为每个连通块都可以交换黑白点。问题在于暴力连边是n2的,而显然实际有用的边其实只有O(n)条。考虑这样一种连边方式:每个点向后缀最小值、前缀第一个比他大的点连边。瞎归纳归纳就可以证明连这些边就够了。这个前缀第一个比他大的随便找都行,比如弄个bit。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<cstdlib>
  5. #include<cstring>
  6. #include<algorithm>
  7. using namespace std;
  8. #define ll long long
  9. #define N 100010
  10. #define P 998244353
  11. char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
  12. int gcd(int n,int m){return m==?n:gcd(m,n%m);}
  13. int read()
  14. {
  15. int x=,f=;char c=getchar();
  16. while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
  17. while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
  18. return x*f;
  19. }
  20. int n,a[N],pre[N],suf[N],fa[N],tree[N],cnt;
  21. inline void chkmax(int &x,int y){if (a[y]>a[x]) x=y;}
  22. inline void chkmin(int &x,int y){if (a[y]<a[x]) x=y;}
  23. int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
  24. void ins(int k,int x){while (k<=n) tree[k]=min(tree[k],x),k+=k&-k;}
  25. int query(int k){int s=n;while (k) s=min(s,tree[k]),k-=k&-k;return s;}
  26. int main()
  27. {
  28. #ifndef ONLINE_JUDGE
  29. freopen("bzoj4881.in","r",stdin);
  30. freopen("bzoj4881.out","w",stdout);
  31. const char LL[]="%I64d\n";
  32. #else
  33. const char LL[]="%lld\n";
  34. #endif
  35. n=read();
  36. for (int i=;i<=n;i++) fa[i]=i,a[i]=read(),tree[i]=n+;a[]=,a[n+]=n+;
  37. pre[]=;for (int i=;i<=n;i++) chkmax(pre[i]=pre[i-],i);
  38. suf[n+]=n+;for (int i=n;i>=;i--) chkmin(suf[i]=suf[i+],i);
  39. for (int i=;i<=n;i++)
  40. if (pre[i]!=i&&suf[i]!=i) {cout<<;return ;}
  41. else
  42. {
  43. if (suf[i]!=i) fa[find(i)]=find(suf[i]);
  44. if (pre[i]!=i) fa[find(i)]=find(query(n+-a[i]));
  45. ins(n+-a[i],i);
  46. }
  47. for (int i=;i<=n;i++) if (find(i)==i) cnt++;
  48. int ans=;while (cnt--) ans=(ans<<)%P;
  49. cout<<ans;
  50. return ;
  51. }

  另一种暴力是一个显然的dp,即设f[i][j]为dp到第i位时,不包含i的集合的最大值是第j个数的方案数。则有f[i][i-1]=Σf[i-1][j] (a[i]>a[j],j<i-1),f[i][j]=f[i-1][j] (a[i]>a[i-1],j<i-1)。将dp数组看成一维的,显然就可以用线段树优化了,即开一棵以a[]为下标的线段树,对f[i][i-1]在线段树上查询前缀更新,如果a[i]<a[i-1]就给整个线段树清零。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<cstdlib>
  5. #include<cstring>
  6. #include<algorithm>
  7. using namespace std;
  8. #define ll long long
  9. #define N 100010
  10. #define P 998244353
  11. char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
  12. int gcd(int n,int m){return m==?n:gcd(m,n%m);}
  13. int read()
  14. {
  15. int x=,f=;char c=getchar();
  16. while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
  17. while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
  18. return x*f;
  19. }
  20. int n,a[N],L[N<<],R[N<<],tree[N<<],lazy[N<<];
  21. void update(int k){tree[k]=,lazy[k]=;}
  22. void down(int k){update(k<<),update(k<<|),lazy[k]=;}
  23. void up(int k){tree[k]=(tree[k<<]+tree[k<<|])%P;}
  24. void build(int k,int l,int r)
  25. {
  26. L[k]=l,R[k]=r;
  27. if (l==r) return;
  28. int mid=l+r>>;
  29. build(k<<,l,mid);
  30. build(k<<|,mid+,r);
  31. }
  32. void add(int k,int p,int x)
  33. {
  34. if (L[k]==R[k]) {tree[k]+=x;return;}
  35. if (lazy[k]) down(k);
  36. int mid=L[k]+R[k]>>;
  37. if (p<=mid) add(k<<,p,x);
  38. else add(k<<|,p,x);
  39. up(k);
  40. }
  41. int query(int k,int l,int r)
  42. {
  43. if (L[k]==l&&R[k]==r) return tree[k];
  44. if (lazy[k]) down(k);
  45. int mid=L[k]+R[k]>>;
  46. if (r<=mid) return query(k<<,l,r);
  47. else if (l>mid) return query(k<<|,l,r);
  48. else return (query(k<<,l,mid)+query(k<<|,mid+,r))%P;
  49. }
  50. int main()
  51. {
  52. #ifndef ONLINE_JUDGE
  53. freopen("bzoj4881.in","r",stdin);
  54. freopen("bzoj4881.out","w",stdout);
  55. const char LL[]="%I64d\n";
  56. #else
  57. const char LL[]="%lld\n";
  58. #endif
  59. n=read();
  60. for (int i=;i<=n;i++) a[i]=read();
  61. build(,,n);add(,,);
  62. for (int i=;i<=n;i++)
  63. {
  64. int x=query(,,a[i]);
  65. if (a[i]<a[i-]) update();
  66. add(,a[i-],x);
  67. }
  68. cout<<tree[];
  69. return ;
  70. }

BZOJ4881 线段游戏(二分图+树状数组/动态规划+线段树)的更多相关文章

  1. st表、树状数组与线段树 笔记与思路整理

    已更新(2/3):st表.树状数组 st表.树状数组与线段树是三种比较高级的数据结构,大多数操作时间复杂度为O(log n),用来处理一些RMQ问题或类似的数列区间处理问题. 一.ST表(Sparse ...

  2. bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Stat ...

  3. [BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】

    题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过 ...

  4. [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

    题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...

  5. POJ 1195 Mobile phones (二维树状数组或线段树)

    偶然发现这题还没A掉............速速解决了............. 树状数组和线段树比较下,线段树是在是太冗余了,以后能用树状数组还是尽量用......... #include < ...

  6. 【BZOJ3196】二逼平衡树(树状数组,线段树)

    [BZOJ3196]二逼平衡树(树状数组,线段树) 题面 BZOJ题面 题解 如果不存在区间修改操作: 搞一个权值线段树 区间第K大--->直接在线段树上二分 某个数第几大--->查询一下 ...

  7. BZOJ.4553.[HEOI2016&TJOI2016]序列(DP 树状数组套线段树/二维线段树(MLE) 动态开点)

    题目链接:BZOJ 洛谷 \(O(n^2)\)DP很好写,对于当前的i从之前满足条件的j中选一个最大值,\(dp[i]=d[j]+1\) for(int j=1; j<i; ++j) if(a[ ...

  8. P3157 [CQOI2011]动态逆序对(树状数组套线段树)

    P3157 [CQOI2011]动态逆序对 树状数组套线段树 静态逆序对咋做?树状数组(别管归并QWQ) 然鹅动态的咋做? 我们考虑每次删除一个元素. 减去的就是与这个元素有关的逆序对数,介个可以预处 ...

  9. HDU 4247 Pinball Game 3D(cdq 分治+树状数组+动态规划)

    Pinball Game 3D Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

随机推荐

  1. Entity Framework中的几种加载方式

            在Entity Framework中有三种加载的方式,分别是延迟加载,自动加载和显示加载.下面用一个例子来说明:现在有两个表,一个是资料表(Reference),另外一个表是资料分类表 ...

  2. C#特性的简单介绍

    特性应该我们大多接触过,比喻经常使用的[Obsolete],[Serializable]等下面我就主要介绍一个特性的一些用法 摘自MSDN定义:用以将元数据或声明信息与代码(程序集.类型.方法.属性等 ...

  3. PHASER3 设置场景SCENE SLEEPING休眠和WAKE唤醒

    A good way to set scene stop when hidden and run while visible again ! 使用sleep和wake方法的好处: 1.可以彻底让sce ...

  4. vue cli 3 +jquery

    const webpack = require('webpack')module.exports = { // baseUrl type:{string} default:'/' // 将部署应用程序 ...

  5. HPUX修改disk实例号--11.31only

    有时由于一些原因或者用户的要求,需要修改Disk的实例号,这里简单介绍如何手工进行修改. 在修改之前需要做一些准备工作,即先将stale状态的设备文件清理掉,具体步骤如下: 使用ioscan命令列出s ...

  6. [T-ARA][HOLIDAY]

    歌词来源:http://music.163.com/#/song?id=22704407 HOLI HOLI DAY [HOLI HOLI DAY] 뚜뚜 뚜루루 [ddu-ddu ddu-lu-lu ...

  7. Qt绘图

    Qt绘图的设置 QPainter::Antialiasing // 反锯齿 QPainter::TextAntialiasing // 文字反锯齿 QPainter::SmoothPixmapTran ...

  8. 第五次ScrumMeeting博客

    第五次ScrumMeeting博客 本次会议于10月29日(日)22时整在3公寓725房间召开,持续15分钟. 与会人员:刘畅.辛德泰.窦鑫泽.张安澜.赵奕. 1. 每个人的工作(有Issue的内容和 ...

  9. win10与linux双系统切换时间不一致的调整

    按照Linux系统之后再切换回到win10后,我发现win10的时间不再是北京时间,而是比北京时间多了整整8小时,之后百度找到了问题来源,这里给出解决方法. 如果安装了 Windows 和 Linux ...

  10. 2018软工实践—Alpha冲刺(4)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 协助前后端接口的开发 测试项目运行的服务器环 ...