"Ray, Pass me the dishes!" UVALive - 3938 (线段树)

灰太狼 2021-03-28 14:42 483阅读 0赞

70

题意:给出询问a,b求出a,b区段内的最大子串

思路:

不难想象,一个区段的最大子串要么为其两个子区段的最大子串,要么第一个子串的最大后缀加上第二个子串的最大前缀。因此我们需要维护每一个串的最大前缀,最大后缀,以及最大子串。但是同时需要考虑到,子串的情况会和坐标有关,因此我们不选择直接维护子串的值,而是选择维护串的起始位置和终止位置,再通过前缀和相减来得到串的值的大小。

AC代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #define lson(x) x<<1
  5. #define rson(x) x<<1|1
  6. using namespace std;
  7. const int size=500005;
  8. typedef pair<int,int> Interval;
  9. typedef pair<int,int> pii;
  10. typedef long long LL;
  11. LL Sum[size];
  12. struct Tree{
  13. int l,r;
  14. pii max_sub;
  15. int max_perfix;
  16. int max_suffix;
  17. }tree[size<<2];
  18. inline int md(int l,int r){return (l+r)>>1;}
  19. inline LL sum(pii x)
  20. {
  21. return Sum[x.second]-Sum[x.first-1];
  22. }
  23. pii Inter_compare(pii a,pii b)
  24. {
  25. LL x=sum(a),y=sum(b);
  26. if(x!=y) return x>y?a:b;
  27. return a<b?a:b;
  28. }
  29. inline Tree combine(Tree a,Tree b)
  30. {
  31. Tree temp;
  32. temp.l=a.l;
  33. temp.r=b.r;
  34. temp.max_perfix=Inter_compare(Interval(a.l,a.max_perfix),Interval(a.l,b.max_perfix)).second;
  35. temp.max_suffix=Inter_compare(Interval(a.max_suffix,b.r),Interval(b.max_suffix,b.r)).first;
  36. temp.max_sub=Inter_compare(Interval(a.max_suffix,b.max_perfix),Inter_compare(a.max_sub,b.max_sub));
  37. return temp;
  38. }
  39. void build(int k,int l,int r)
  40. {
  41. if(l==r)
  42. {
  43. tree[k].l=l;
  44. tree[k].r=r;
  45. tree[k].max_suffix=l;
  46. tree[k].max_perfix=l;
  47. tree[k].max_sub=Interval(l,r);
  48. return ;
  49. }
  50. int mid=md(l,r);
  51. build(lson(k),l,mid);
  52. build(rson(k),mid+1,r);
  53. tree[k]=combine(tree[lson(k)],tree[rson(k)]);
  54. }
  55. Tree query(int k,int l,int r)
  56. {
  57. if(l<=tree[k].l&&r>=tree[k].r)
  58. {
  59. return tree[k];
  60. }
  61. int mid=md(tree[k].l,tree[k].r);
  62. if(r<=mid) return query(lson(k),l,r);
  63. if(l>mid)return query(rson(k),l,r);//l不能加等于号
  64. return combine(query(lson(k),l,r),query(rson(k),l,r));
  65. }
  66. int main()
  67. {
  68. int n,m;
  69. int cnt=0;
  70. while(~scanf("%d%d",&n,&m))
  71. {
  72. memset(Sum,0,sizeof(Sum));
  73. for(int i=1;i<=n;i++)
  74. {
  75. int temp;
  76. scanf("%d",&temp);
  77. Sum[i]=Sum[i-1]+temp;
  78. }
  79. build(1,1,n);
  80. printf("Case %d:\n",++cnt);
  81. while(m--)
  82. {
  83. int l,r;
  84. scanf("%d%d",&l,&r);
  85. pii ans=query(1,l,r).max_sub;
  86. printf("%d %d\n",ans.first,ans.second);
  87. }
  88. }
  89. }

发表评论

表情:
评论列表 (有 0 条评论,483人围观)

还没有评论,来说两句吧...

相关阅读

    相关 线段

    线段树入门: 转载博客:[点击打开链接][Link 1] 前几天开始接触线段树,其一些基本的操作还是很容易理解的,但是区间更新我着实理解了好一会(因该是本人太菜),今天有时

    相关 线段

    一 概述 线段树,类似区间树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(l