bzoj 1500 splay伸展树

本文详细介绍了如何使用Splay树实现区间操作,并指出了实现过程中需要注意的关键事项,包括翻转操作、懒惰标记、树节点更新策略等。通过实例演示了如何插入、删除、查询、翻转区间及获取最大值等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

splay可以支持区间操作
简单说几个需要注意的事项
1。在实现翻转的时候,切记不可以直接rev[key_value]^=1,需要调用一次update_rev(key_value),直接翻转左右孩子,首次标记的时候不能直接标记等下一次再翻转。
2。same[]懒惰标记不能记录修改的值,只记录修改与否即可,键值储存需要修改的值就可以了。因为这道题不清楚修改的值是什么~可正可负

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include<string.h>
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
#define exp 1e-8
#define INF 0x3f3f3f3f
#define ll long long
#define set(a,b) memset(a,b,sizeof(a));
#define set(a,b) memset(a,b,sizeof(a));
#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)
#define for0(a,b) for(int a=0;a<=b;a++)//0---(b)
void bug(string st="bug")
{cout<<st<<endl;}
template<typename __ll>
inline void READ(__ll &m){
    __ll x=0,f=1;char ch=getchar();
    while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    m=x*f;
}
template<typename __ll>
inline void read(__ll &m){READ(m);}
template<typename __ll>
inline void read(__ll &m,__ll &a){READ(m);READ(a);}
template<typename __ll>
inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}
const int MAXN=500010;
#define dat int
#define Key_value ch[ch[root][1]][0]
struct splaytree
{
    int ch[MAXN][2];  //孩子
    int pre[MAXN];   //父亲
    int rev[MAXN];   //标志
    dat key[MAXN];  //键值
    int size[MAXN];  //大小
    int same[MAXN];
    int sum[MAXN];
    int maxn[MAXN],lmaxn[MAXN],rmaxn[MAXN];
    int root,tot1;  //根  结点大小
    int s[MAXN],tot2;  //删除用的数组,记录删除了那些点,重复利用删除的点
    void addnode(int &r,int father,dat k)
    {
        if(tot2) r=s[tot2--];
        else r=++tot1;
        ch[r][0]=ch[r][1]=rev[r]=0;
        pre[r]=father;
        key[r]=k;
        size[r]=1;
        same[r]=0;
        sum[r]=k;
        lmaxn[r]=rmaxn[r]=maxn[r]=k;
    }
    void push_up(int r)
    {
       int lson=ch[r][0],rson=ch[r][1];
       size[r]=1+size[lson]+size[rson];
       sum[r]=sum[lson]+sum[rson]+key[r];
       lmaxn[r]=max(lmaxn[lson],sum[lson]+key[r]+max(0,lmaxn[rson]));
       rmaxn[r]=max(rmaxn[rson],sum[rson]+key[r]+max(0,rmaxn[lson]));
       maxn[r]=max(0,rmaxn[lson])+key[r]+max(0,lmaxn[rson]);
       maxn[r]=max(maxn[r],max(maxn[lson],maxn[rson]));
    }
    void update_rev(int r)
    {
        if(!r) return ;
        swap(lmaxn[r],rmaxn[r]);
        swap(ch[r][0],ch[r][1]);
        rev[r]^=1; //翻来翻去
    }
    void update_same(int r,int c)
    {
        if(!r) return ;
        key[r]=c;   //当same[r]==1  意味孩子节点都等于key[r]
        sum[r]=size[r]*c;
        lmaxn[r]=rmaxn[r]=maxn[r]=max(c,sum[r]);
        same[r]=1;
    }
    void push_down(int r)
    {
        if(rev[r])
        {
            update_rev(ch[r][0]);
            update_rev(ch[r][1]);
            rev[r]=0;
        }
        if(same[r])
        {
            update_same(ch[r][0],key[r]);
            update_same(ch[r][1],key[r]);
            same[r]=0;
        }
    }
    void build(int &x,int father,int l,int r,dat *str)
    {  //当前x在调用build的时候才建立,,注意根标号是x
        if(l>r)  return ;
        int mid=l+r>>1;
        addnode(x,father,str[mid]);
        build(ch[x][0],x,l,mid-1,str);
        build(ch[x][1],x,mid+1,r,str);
        push_up(x);
    }
    void init()
    {
        root=tot1=tot2=0;
        ch[0][0]=ch[0][1]=pre[0]=size[0]=rev[0]=0;
        same[0]=sum[0]=0;
        maxn[0]=lmaxn[0]=rmaxn[0]=-INF;
        addnode(root,0,-1);   //在这里创建收尾区间,方便操作
        addnode(ch[root][1],root,-1);
        push_up(ch[root][1]);
        push_up(root);
    }
    void rotate(int x,int kind)
    {
        int y=pre[x];
        int z=pre[y];
        push_down(y);
        push_down(x);
        ch[y][!kind]=ch[x][kind];
        pre[ch[x][kind]]=y;
        if(z)   ch[z][ch[z][1]==y] = x;
        pre[x]=pre[y];
        ch[x][kind]=y;
        pre[y]=x;
        push_up(y);
    }
    void splay(int r,int goal)
    {
        push_down(r);
        while(pre[r]!=goal)    //各类push_down已经在rotate中执行
        {
            if(pre[pre[r]]==goal)
            {
                rotate(r,ch[pre[r]][0]==r);
                continue;
            }
            int y=pre[r];
            int z=pre[y];
            int kind=  ch[z][0]==y;
            if(ch[y][kind]==r)
                rotate(r,!kind),rotate(r,kind);
            else rotate(y,kind),rotate(r,kind);
        }
        push_up(r);
        if(goal==0)  root=r;
    }
    int get_kth(int r,int k)  //寻找r根子树下面的第k大
    {
        push_down(r);
        int t=size[ch[r][0]]+1;
        if(k==t) return r;
        if(t>k) return get_kth(ch[r][0],k);
        return get_kth(ch[r][1],k-t);
    }
    void select(int a,int b)  //将第a个设为根,第b个设为根的右孩子
    {                         //根的右孩子的左孩子  代表区间[a+1,b-1]
        splay(get_kth(root,a),0);
        splay(get_kth(root,b),root);
    }
    void insert(int pos,int len,dat *str)
    {
        select(pos,pos+1);
        build(Key_value,ch[root][1],0,len-1,str);
        push_up(ch[root][1]);
        push_up(root);
    }
    void erase(int r)    //重复利用删除的结点
    {
        if(!r)return ;
        s[++tot2]=r;
        erase(ch[r][0]);
        erase(ch[r][1]);
    }
    void Del(int pos,int len)
    {
        select(pos,pos+len+1);
        erase(Key_value);
        pre[Key_value]=0;
        Key_value=0;
        push_up(ch[root][1]);
        push_up(root);
    }
    void make_same(int pos,int len,int c)
    {
        select(pos,pos+len+1);
        update_same(Key_value,c);
        push_up(ch[root][1]);
        push_up(root);
    }
    void reverse(int pos,int len)  //翻转如此就好
    {
        select(pos,pos+len+1);
        update_rev(Key_value);  
        push_up(ch[root][1]);
        push_up(root);
/*
        select(pos,pos+len+1);
        rev[key_value]^=1;
        这样子写就是错误的  
        谨记~~~
*/
    }
    void get_sum(int pos,int len)
    {
        select(pos,pos+len+1);
        printf("%d\n",sum[Key_value]);
    }
    void get_max()
    {
        select(1,size[root]);
        printf("%d\n",max(maxn[Key_value],max(lmaxn[Key_value],rmaxn[Key_value])));
    }
    void InOrder(int r){    //中序
        if(r==0)
            return;
        InOrder(ch[r][0]);
        printf("%c",key[r]);
        InOrder(ch[r][1]);
    }

}t;
int str[MAXN];
int main()
{
        int n,m;
        int x,y,z;
        char op[20];
        scanf("%d %d",&n,&m);
        t.init();
        for(int i=0;i<n;i++)
            scanf("%d",&str[i]);
        t.insert(1,n,str);
        while(m--)
        {
            scanf("%s",&op);
            switch(op[2])
            {
            case 'S':
                scanf("%d %d",&x,&y);
                for(int i=0;i<y;i++)
                    scanf("%d",&str[i]);
                t.insert(x+1,y,str);
                break;
            case 'L':
                scanf("%d %d",&x,&y);
                t.Del(x,y);
                break;
            case 'K':
                scanf("%d %d %d",&x,&y,&z);
                t.make_same(x,y,z);
                break;
            case 'V':
                scanf("%d %d",&x,&y);
                t.reverse(x,y);
                break;
            case 'T':
                scanf("%d %d",&x,&y);
                t.get_sum(x,y);
                break;
            case 'X':
                t.get_max();
                break;
            }
        }
}
























内容概要:本文详细探讨了机组组合优化模型的构建,旨在通过合理安排各类发电机组的启停计划和优化出力分配,实现电力系统在经济性和稳定性上的最佳平衡。文章首先介绍了电力系统的四大主要组件——传统火电机组、风电机组、光伏机组和储能系统的参数及运行特性。接着,围绕最小化系统总运行成本这一目标,设计了优化目标函数,并明确了包括功率平衡约束、机组出力上下限约束、风光发电功率约束、弃风弃光约束、爬坡速率约束、储能系统荷电状态约束、充放电功率约束和充放电互斥约束在内的多项约束条件。最后,文章列出了求解机组组合优化模型所需的关键变量,如传统机组的开停状态、机组出力、启停成本、风电光伏实际出力、弃风弃光比例及储能系统的充放电功率和荷电状态,以实现系统的经济调度和可再生能源的最大化利用。 适合人群:从事电力系统研究、规划和调度工作的工程师和技术人员,以及对电力系统优化感兴趣的科研人员。 使用场景及目标:①帮助电力系统工程师理解不同类型发电机组的特点及其对系统稳定性、经济性和环保性的影响;②为制定合理的电力系统调度策略提供理论依据和技术支持;③促进可再生能源的有效整合,提高电力系统的灵活性和可靠性。 其他说明:本文提供的模型和方法不仅适用于当前的电力系统,也可为未来含高比例可再生能源接入的电力系统提供参考。文中涉及的具体数学公式和参数设定为实际应用提供了详细的指导,有助于提升电力系统的运行效率和经济效益。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值