HDU 1754 I Hate It (Splay 区间操作)

题目大意

维护一个序列,支持两种操作
操作一:将第x个元素的值修改为y
操作二:询问区间【x,y】内的元素的最大值

解题分析

splay的区间操作,事先加入两个编号最小和最大的点防止操作越界。
具体的区间操作类似于线段树。

参考程序

#include <bits/stdc++.h>
using namespace std;
const int INF=2000000000;
const int N=200008;
int a[N];

class splay_tree
{
public:
    struct node
    {
        int id,val,mx;
        node *l,*r,*f;
        node(int _id=0,int _val=0,int _mx=0,node *_f=NULL,node *_l=NULL,node *_r=NULL):
        mx(_mx),id(_id),val(_val),f(_f),l(_l),r(_r){}
    }*rt;
    void pushup(node *x)
    {
        node *l=x->l,*r=x->r;
        x->mx=x->val;
        if (l) x->mx=max(x->mx,l->mx);
        if (r) x->mx=max(x->mx,r->mx);
    }
    void right(node *x,node *&rt)
    {
        node *y=x->f,*z=y->f;
        if (y==rt) rt=x; else if (y==z->l) z->l=x; else z->r=x;
        if (x->r) x->r->f=y; y->f=x; x->f=z;
        y->l=x->r; x->r=y;
        pushup(y); pushup(x);
    }
    void left(node *x,node *&rt)
    {
        node *y=x->f,*z=y->f;
        if (y==rt) rt=x; else if (y==z->l) z->l=x; else z->r=x;
        if (x->l) x->l->f=y; y->f=x; x->f=z;
        y->r=x->l; x->l=y;
        pushup(y); pushup(x);
    }
    void splay(node *x,node *&rt)
    {
        while (x!=rt)
        {
            node *y=x->f,*z=y->f;
            if (y==rt) if (x==y->l) right(x,rt); else left(x,rt); 
            else if (y==z->l) if (x==y->l) {right(y,rt);right(x,rt);} else {left(x,rt);right(x,rt);} 
                 else if (x==y->r) {left(y,rt);left(x,rt);} else {right(x,rt);left(x,rt);}
        }
    }
    void del(node *rt)
    {
        if (!rt) return;
        del(rt->l);
        del(rt->r);
        delete rt;
    }
    splay_tree(){rt=NULL;}
    ~splay_tree()
    {
        del(rt);
    }
    void build(int l,int r,node *&x,node *f)
    {
        if (l>r) return;
        int m=l+r>>1;
        x=new node(m,a[m],a[m],f);
        if (l==r) return;
        build(l,m-1,x->l,x);
        build(m+1,r,x->r,x);
        pushup(x);
    }
    void find(int id,node* &rt)
    {   
        node *x=rt;
        while (x->id!=id)
        {
            if (id<x->id) x=x->l; else x=x->r;
        }
        splay(x,rt);
    }
    void update(int id,int val)
    {   
        node *x=rt;
        while (x->id!=id)
        {
            if (id<x->id) x=x->l; else x=x->r;
        }
        x->val=val;
        splay(x,rt);
    }
    int query(int x,int y)
    {
        find(x-1,rt);
        find(y+1,rt->r);
        return rt->r->l->mx;
    }
    void visit(node *rt)
    {
        if (!rt) return;
        cout<<" id = "<<rt->id<<" val = "<<rt->val;
        cout<<" lson = "<<(rt->l?rt->l->id:0);
        cout<<" rson = "<<(rt->r?rt->r->id:0)<<endl;
        visit(rt->l);
        visit(rt->r);
    }
};
int main()
{
    cin.sync_with_stdio(0);
    int n,m;
    while (cin>>n>>m)
    {
        splay_tree T;
        for (int i=1;i<=n;i++) cin>>a[i];
        a[0]=a[n+1]=0;
        T.build(0,n+1,T.rt,NULL);   
        for (int i=1;i<=m;i++) 
        {
            string s;int x,y;
            cin>>s>>x>>y;
            if (s[0]=='Q')
                cout<<T.query(x,y)<<endl;
            else
                T.update(x,y);
        }
    }
}

转载于:https://www.cnblogs.com/rpSebastian/p/6804487.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值