Hotel POJ - 3667(线段树 + 区间合并

本文详细介绍了一种高效的数据结构——线段树,通过具体的操作案例解释了线段树的构造、查询及更新等核心操作,并提供了完整的代码实现。

题意: 给定长度为n的区间 ,有2个操作:

操作1: 在区间中靠左放k个元素,输出新放入元素中最左边的位置,如果放不下输出 0;

操作2 : 清空 l 到 l+w-1这一段区间的元素

 

这里有一个状态转移方程(即线段树的上推方式):

线段树区间pos中储存  lcon--从区间左端L最大连续的区间长度 , rcon--从线段树右端R最大连续的区间长度 ,mcon 区间内最大的区间长度

则:      t[pos].mcon = max{ t[Lpos].rcon+t[Rpos].lcon  ,t[Lpos].mcon  ,t[Rpos].mcon );

             t[pos].lcon = t[Lpos].lcon+(t[Rpos],lcon);  t[pos].rcon = t[Rpos].rcon+(t[Lpos].rcon) (如果左或右区间整段连续,就加上括号里面的部分

 

lazy标记的下移(对整段空或整段满的区间进行标记):

void pushdown( int L ,int R, int pos){
    if( t[pos].tag!=0 && t[pos].tag!=1 ) return ;
    int Mid;
     t[posl].tag = t[posr].tag =t[pos].tag;
     t[posl].mcon = t[posl].lcon = t[posl].rcon = t[pos].tag ? mid - L+1 : 0 ;
     t[posr].mcon = t[posr].lcon = t[posr].rcon = t[pos].tag ? R-mid : 0 ;
     t[pos].tag = -1;
     return ;
}

 

查询:

判断能否放下: 比较k与总区间最大连续区间长度t[ 1 ].mcon 的大小

查询新放入元素最左坐标:如果左区间最大连续空区间大于目标长度就一直查询左区间,直到查询不了就判断左区间右连续加上右区间左连续可不可以,可以就输出结果,不行的话在查询右区间                                                                

int query(  int L ,int R ,int pos ,int w ){
     if( L==R ) return L;
    // cout<< L <<' '<<R << ' '<<w<<endl;
     pushdown( L ,R ,pos);
     int Mid;
     if( t[posl].mcon >= w ) return query( lson , w);                                           //优先查左边
     else if( t[posl].rcon + t[posr].lcon >= w) return mid - t[posl].rcon +1 ; //查到左边放不下了,输出区间放在中间的结果
     else return query( rson ,w);                                                                            //中间放不了,最末查询右边
}

更新比较平常 ,就不说了

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define posl pos<<1
#define posr pos<<1|1
#define lson L ,mid ,posl
#define rson mid+1 ,R ,posr
#define Mid mid=(L+R)>>1

struct tree{
     int lcon ,rcon ,mcon;
     int  tag;
} t[50005<<2];
void pushup( int L ,int R ,int pos){
     t[pos].lcon = t[posl].lcon;
     t[pos].rcon = t[posr].rcon;
     int Mid;
     if( t[pos].lcon == mid - L +1 ) t[pos].lcon += t[posr].lcon;
     if( t[pos].rcon == R - mid ) t[pos].rcon += t[posl].rcon;
     t[pos].mcon = max( t[posl].rcon+t[posr].lcon ,max( t[posl].mcon  ,t[posr].mcon));
}

void pushdown( int L ,int R, int pos){
    if( t[pos].tag!=0 && t[pos].tag!=1 ) return ;
    int Mid;
     t[posl].tag = t[posr].tag =t[pos].tag;
     t[posl].mcon = t[posl].lcon = t[posl].rcon = t[pos].tag ? mid - L+1 : 0 ;
     t[posr].mcon = t[posr].lcon = t[posr].rcon = t[pos].tag ? R-mid : 0 ;
     t[pos].tag = -1;
     return ;
}

void build( int L ,int R ,int pos){
     t[pos].tag = -1;
     t[pos].lcon = t[pos].rcon = t[pos].mcon = R - L +1;
     if( L == R) return ;
     int Mid;
     build( lson);
     build( rson);
}

void updata( int L ,int R ,int pos ,int l,int r,int v ){
     if( L>= l && R <= r ){

        t[pos].mcon = t[pos].rcon = t[pos].lcon = v ? R - L +1 : 0 ;
        t[pos].tag = v;
        return ;
     }
     if( L == R)return;
     pushdown( L ,R ,pos);
     int Mid;
     if( l <= mid ) updata( lson ,l ,r ,v);
     if( mid < r) updata( rson ,l ,r ,v);
     pushup( L ,R ,pos);
}

int query(  int L ,int R ,int pos ,int w ){
     if( L==R ) return L;
    // cout<< L <<' '<<R << ' '<<w<<endl;
     pushdown( L ,R ,pos);
     int Mid;
     if( t[posl].mcon >= w ) return query( lson , w);                                           //优先查左边
     else if( t[posl].rcon + t[posr].lcon >= w) return mid - t[posl].rcon +1 ; //查到左边放不下了,输出区间放在中间的结果
     else return query( rson ,w);                                                                            //中间放不了,最末查询右边
}
int main( ){
     int n,m;
     scanf( "%d%d" ,&n ,&m);
     build( 1 ,n ,1);
     while( m-- ){
         int op ,k ,l ,r;
         scanf("%d" ,&op);
         if( op ==1){
             scanf("%d" ,&k);
             if( t[1].mcon >=k){
                 l=query( 1 ,n ,1 ,k);
                 updata( 1 , n ,1 ,l ,l+k-1, 0);
                 printf("%d\n" ,l);
             }
             else printf("0\n");
         }
         else{
             scanf("%d%d",&l ,&r);
             updata( 1 ,n ,1 ,l ,l+r-1,1);
         }
     }
     return 0;
}

 

转载于:https://www.cnblogs.com/-ifrush/p/10632421.html

基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究(Matlab代码实现)内容概要:本文围绕“基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究”,介绍了利用Matlab代码实现配电网可靠性的仿真分析方法。重点采用序贯蒙特卡洛模拟法对配电网进行长时间段的状态抽样与统计,通过模拟系统元件的故障与修复过程,评估配电网的关键可靠性指标,如系统停电频率、停电持续时间、负荷点可靠性等。该方法能够有效处理复杂网络结构与设备时序特性,提升评估精度,适用于含分布式电源、电动汽车等新型负荷接入的现代配电网。文中提供了完整的Matlab实现代码与案例分析,便于复现和扩展应用。; 适合人群:具备电力系统基础知识和Matlab编程能力的高校研究生、科研人员及电力行业技术人员,尤其适合从事配电网规划、运行与可靠性分析相关工作的人员; 使用场景及目标:①掌握序贯蒙特卡洛模拟法在电力系统可靠性评估中的基本原理与实现流程;②学习如何通过Matlab构建配电网仿真模型并进行状态转移模拟;③应用于含新能源接入的复杂配电网可靠性定量评估与优化设计; 阅读建议:建议结合文中提供的Matlab代码逐段调试运行,理解状态抽样、故障判断、修复逻辑及指标统计的具体实现方式,同时可扩展至不同网络结构或加入更多不确定性因素进行深化研究。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值