[2016北京集训试题17]数组-[线段树]

Description

Solution

线段树乱搞orz。

定义pre[i]为从i点往前找到第1个颜色和点i相同的点。树状数组记录max和sum。max记录区间[l,r]内pre的最大值,sum记录区间[l,r]内的答案总和。注意:最终的答案是取

$n*(n+1)/2-\sum _{r=1}^{n}max(pre[i],1\leq i\leq r)$,即枚举所有子区间的右节点,找最左的左节点。因此,sum[x](记录区间[l,r])在更新的时候,sum[x的左节点]可以直接加上,而对于x的右节点要保证区间[mid+1,r]的数和max[x的左节点]取最大值。这个可以在log(n)内搞定。

然后。。就ok了。

我怕是学了个假的线段树。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,m;
int col[N],pre[N];
set<int>id[N];
ll sum[N<<2],mx[N<<2];
ll solve(int k,int l,int r,ll x)
{
    if (l==r) return max(x,mx[k]);
    int mid=(l+r)/2;
    if (mx[k]<=x) return x*(r-l+1);
    if (mx[k<<1]<=x) return 1ll*x*(mid-l+1)+solve(k<<1|1,mid+1,r,x);
    return solve(k<<1,l,mid,x)+sum[k]-sum[k<<1];
}
void pushup(int k,int mid,int r)
{
    mx[k]=max(mx[k<<1],mx[k<<1|1]);
    sum[k]=sum[k<<1]+solve(k<<1|1,mid+1,r,mx[k<<1]);
}
void modify(int k,int l,int r,int x,int y)
{
    if (l==r){sum[k]=mx[k]=y;return;}
    int mid=(l+r)/2;
    if (x<=mid) modify(k<<1,l,mid,x,y);else modify(k<<1|1,mid+1,r,x,y);
    pushup(k,mid,r);
}
void build(int k,int l,int r)
{
    if (l==r){sum[k]=mx[k]=pre[l];return;}
    int mid=(l+r)/2;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    pushup(k,mid,r);
}
set<int>::iterator q,l,r;
int x,to;
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) id[i].insert(0);
    for (int i=1;i<=n;i++) 
    {
        scanf("%d",&col[i]);
        pre[i]=*(--id[col[i]].end());
        id[col[i]].insert(i);
    }
    build(1,1,n);
    int Q,opt;
    scanf("%d",&Q);
    while (Q--)
    {
        scanf("%d",&opt);
        if (!opt) printf("%lld\n",1ll*n*(n+1)/2-sum[1]);
        else
        {
            scanf("%d%d",&x,&to);
            q=id[col[x]].find(x);
            l=r=q;l--;r++;
            if (r!=id[col[x]].end())
            {
                pre[*r]=*l;
                modify(1,1,n,*r,*l);
            }
            id[col[x]].erase(q); 
            col[x]=to;id[to].insert(x);
            q=id[to].find(x);
            l=r=q;l--;r++;
            if (r!=id[to].end())
            {
                pre[*r]=x;
                modify(1,1,n,*r,x);
            }
            pre[x]=*l;
            modify(1,1,n,x,*l);
             
        }
    }
}

 

转载于:https://www.cnblogs.com/coco-night/p/9733342.html

内容概要:本文详细介绍了基于Simulink平台构建的锂电池供电与双向DCDC变换器智能切换工作的仿真模型。该模型能够根据锂离子电池的状态荷电(SOC)自动或手动切换两种工作模式:一是由锂离子电池通过双向DCDC变换器向负载供电;二是由直流可控电压源为负载供电并同时通过双向DCDC变换器为锂离子电池充电。文中不仅提供了模式切换的具体逻辑实现,还深入探讨了变换器内部的电压电流双环控制机制以及电池热管理模型的关键参数设定方法。此外,针对模型使用过程中可能遇到的问题给出了具体的调试建议。 适用人群:从事电力电子、新能源汽车、储能系统等领域研究和技术开发的专业人士,尤其是那些希望深入了解锂电池管理系统及其与电源转换设备交互机制的研究者和工程师。 使用场景及目标:适用于需要评估和优化锂电池供电系统的性能,特别是涉及双向DCDC变换器的应用场合。通过学习本文提供的理论知识和实践经验,可以帮助使用者更好地理解和掌握相关技术细节,从而提高实际项目的设计效率和可靠性。 其他说明:为了确保仿真的准确性,在使用该模型时需要注意一些特定条件,如仿真步长限制、电池初始SOC范围以及变换器电感参数的选择等。同时,对于可能出现的震荡发散现象,文中也提供了一种有效的解决办法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值