美文网首页线段树
Fruits(线段树)

Fruits(线段树)

作者: weiers | 来源:发表于2018-05-14 17:12 被阅读0次

题目

https://www.nowcoder.com/acm/contest/119/M

题目大意

给你n个节点,每个节点有一个值。有m个操作。操作1是区间更新值为x,操作2是查询区间被切成k段的最大“优雅值”。
优雅值的定义:几段连续的所有数字都不相同的区间中的元素个数和。如3 4 4 4 5的优雅值为4, 3 4 4 5的优雅值为3。3 4 4 5可被切成2段:{3 4},{4 5}优雅值变为4。

算法思路

  • 很明显的线段树。理解题意后我们可以知道,只需要多维护左右端点的值就可以了。区间合并的时候,只需要检查左边区间的右端点和右边区间的左端点是不是相等就可以了。
  • tree[rt]:所代表区间的优雅值
    lnode[rt],rnode[rt]:所代表区间的左右端点的值

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=2*1e5+100;
int lnode[maxn<<2];
int rnode[maxn<<2];
int tree[maxn<<2];
int seg[maxn<<2];
void pushup(int rt){
 tree[rt]=tree[rt*2]+tree[rt*2+1];
 if(rnode[rt*2]==lnode[rt*2+1])
    tree[rt]--;
 lnode[rt]=lnode[rt*2];
 rnode[rt]=rnode[rt*2+1];
}
void pushdown(int rt){
  if(seg[rt]){
    seg[rt*2]=seg[rt];
    seg[rt*2+1]=seg[rt];
    tree[rt*2]=1;
    tree[rt*2+1]=1;
    lnode[rt*2]=rnode[rt*2]=lnode[rt*2+1]=rnode[rt*2+1]=seg[rt];
    seg[rt]=0;
  }
}
void build(int l,int r,int rt){
  seg[rt]=0;
  if(l==r) {
    scanf("%d",&lnode[rt]);
    rnode[rt]=lnode[rt];
    tree[rt]=1;
    return;
  }
  int mid=(l+r)/2;
  build(l,mid,rt*2);
  build(mid+1,r,rt*2+1);
  pushup(rt);
}
void update(int l,int r,int ll,int rr,int add,int rt){
  if(l>=ll&&r<=rr) {
    seg[rt]=add;
    lnode[rt]=rnode[rt]=add;
    tree[rt]=1;
    return;
  }
  pushdown(rt);
  int mid=(l+r)/2;
  if(ll<=mid) {
    update(l,mid,ll,rr,add,rt*2);
  }
  if(rr>mid){
    update(mid+1,r,ll,rr,add,rt*2+1);
  }
  pushup(rt);
}

int query(int l,int r,int ll,int rr,int rt){
  if(l>=ll&&r<=rr){
     return tree[rt];
  }
  int ans=0;int ans1=0;int ans2=0;
  pushdown(rt);
  int mid=(l+r)/2;
  if(ll<=mid) ans1=query(l,mid,ll,rr,rt*2);
  if(rr>mid) ans2=query(mid+1,r,ll,rr,rt*2+1);
  ans=ans1+ans2;
  if(ans1&&ans2&&rnode[rt*2]==lnode[rt*2+1]) ans--;
  return ans;
}

int main(){
  int n,m;
  while(scanf("%d%d",&n,&m)==2){
    build(1,n,1);
    for(int i=0;i<m;i++){
       int op,l,r,x;
       scanf("%d%d%d%d",&op,&l,&    //  cout<<min(r-l+1,ans+x)<<endl;r,&x);
       if(op==1){
           update(1,n,l,r,x,1);

       }
       if(op==2){
         int ans=query(1,n,l,r,1);
         printf("%d\n",min(r-l+1,ans+x));
       }
    }
  }
    return 0;
}

废话

思考清楚 这题不难。
过的人少估计是题意不清

相关文章

  • Fruits(线段树)

    题目 https://www.nowcoder.com/acm/contest/119/M 题目大意 给你n个节点...

  • 算法模板(七) 线段树

    线段树单点操作 线段树区间操作

  • 数据结构-线段树

    实现一个线段树 下面实现的线段树,有三个功能: 把数组构建成一颗线段树 线段树的修改 线段树的查询 303号问题 ...

  • 线段树系列之——区间更新

    第三篇线段树了——重点不在于解决题目,通过题目理解线段树才是重点 前面写了一篇关于线段树的单点更新,线段树的单点更...

  • 线段树模板

    线段树 线段树基本概念 概述 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组)...

  • 线段树专题整理

    待更新 线段树讲解(未读)线段树模板(未读) 模板 求区间总和 A - 敌兵布阵 HDU - 1166 题意 线段...

  • 线段树 02 构建线段树

    构建线段树 线段树的每个节点除了天然的对应一段长度外,不一定赋予其上的意义就是区间元素的和,所以两个节点向上汇聚成...

  • 线段树(区间树)

    线段树:线段树是一种二叉树,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。线段树适用于不变...

  • 线段树

    专题 B线段树求逆序对 C[] D 区间不同值求和

  • 线段树

    [toc] 线段树 实现问题:常用于求数组区间最小值 时间复杂度:(1).建树复杂度:nlogn。(2).线段树算...

网友评论

    本文标题:Fruits(线段树)

    本文链接:https://www.haomeiwen.com/subject/wosjdftx.html