HDU3487 Play with Chain SPLAY 区间分裂,区间合并,区间翻转

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

这道题目涉及了伸展树的分裂特点。

这里注意,当我们要对伸展树做区间分裂操作的时候,我们要添加开始于结尾两个点,用于防范边界情况。输出时特殊判断即可。具体做法是在build建树之前先手动给root一个值0然后给root的右儿子一个值n+1,这样我们就形成了一个区间【0,n+1】,然后我们在将要建立的1-n这棵树放在root的右儿子的左子树上。这里一定要理解。因为以后我们对伸展树的区间操作都是这种方法,假如要提取区间【a,b】那么我们就要将a-1旋转到根,b+1旋转到根的右儿子。然后很显然,右儿子的左子树就是我们所要找的区间。

CUT a,b,c  这个操作要求我们将区间[a,b]分裂出来然后添加在第c个数后面。具体取法与上面相同。这里说一下合并到c之后的方法,做法就是将C旋转到root,然后将右子树的最小值旋转到右子树的根,然后我们在将区间插入右子树的左子树。

FLIP a,b 区间翻转。

这里要注意下。我上面说的a,b都是从左往右第a或第b个数。

总结一下关键字:区间   ,root的右儿子的左子树。

我的splay。。。好长的代码量啊,,,能用treap我一定不用splay。。。。。

 

 

Play with Chain

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2429    Accepted Submission(s): 980


Problem Description
YaoYao is fond of playing his chains. He has a chain containing n diamonds on it. Diamonds are numbered from 1 to n.
At first, the diamonds on the chain is a sequence: 1, 2, 3, …, n.
He will perform two types of operations:
CUT a b c: He will first cut down the chain from the ath diamond to the bth diamond. And then insert it after the cth diamond on the remaining chain.
For example, if n=8, the chain is: 1 2 3 4 5 6 7 8; We perform “CUT 3 5 4”, Then we first cut down 3 4 5, and the remaining chain would be: 1 2 6 7 8. Then we insert “3 4 5” into the chain before 5th diamond, the chain turns out to be: 1 2 6 7 3 4 5 8.

FLIP a b: We first cut down the chain from the ath diamond to the bth diamond. Then reverse the chain and put them back to the original position.
For example, if we perform “FLIP 2 6” on the chain: 1 2 6 7 3 4 5 8. The chain will turn out to be: 1 4 3 7 6 2 5 8

He wants to know what the chain looks like after perform m operations. Could you help him?
 


 

Input
There will be multiple test cases in a test data.
For each test case, the first line contains two numbers: n and m (1≤n, m≤3*100000), indicating the total number of diamonds on the chain and the number of operations respectively.
Then m lines follow, each line contains one operation. The command is like this:
CUT a b c // Means a CUT operation, 1 ≤ a ≤ b ≤ n, 0≤ c ≤ n-(b-a+1).
FLIP a b    // Means a FLIP operation, 1 ≤ a < b ≤ n.
The input ends up with two negative numbers, which should not be processed as a case.
 


 

Output
For each test case, you should print a line with n numbers. The ith number is the number of the ith diamond on the chain.
 


 

Sample Input
  
8 2 CUT 3 5 4 FLIP 2 6 -1 -1
 


 

Sample Output
  
1 4 3 7 6 2 5 8
 


 

Source

 

//SPLAY   分裂区间【a,b】添加在c后面, 区间【a,b】翻转
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>

using namespace std;

#define MAXN 500000

int next[MAXN];
struct nodes
{
    int ch[2],f;
    int key,size,w,col;
}node[MAXN];

void init()
{
    for(int i=0;i<MAXN-10;i++)
        next[i]=i+1;
}

int newnode(int key)
{
    int p=next[0];
    next[0]=next[p];
    node[p].key=key;
    node[p].w=1;
    node[p].col=0;
    node[p].ch[0]=node[p].ch[1]=node[p].f=0;
    return p;
}

void delnode(int p)
{
    next[p]=next[0];
    next[0]=p;
}

struct spt
{
    int root;
    void clear()
    {
        root=0;
    }
    void rotate(int x,int c)
    {
        int y=node[x].f;
        push_down(y);push_down(x);
        node[y].ch[!c]=node[x].ch[c];
        if(node[x].ch[c])
                node[node[x].ch[c]].f=y;
        node[x].f=node[y].f;
        if(node[y].f)
        {
            if(node[node[y].f].ch[0]==y)
                node[node[y].f].ch[0]=x;
            else
                node[node[y].f].ch[1]=x;
        }
        node[x].ch[c]=y;
        node[y].f=x;
        push_up(y);
        if(y==root) root=x;
    }
    void splay(int x,int f)
    {
        push_down(x);
        for(;node[x].f!=f;)
        {
            push_down(node[node[x].f].f),push_down(node[x].f),push_down(x);
            if(node[node[x].f].f==f)
            {
                if(node[node[x].f].ch[0]==x)
                    rotate(x,1);
                else
                    rotate(x,0);
            }
            else
            {
                int y=node[x].f;
                int z=node[y].f;
                if(node[z].ch[0]==y)
                {
                    if(node[y].ch[0]==x)
                        rotate(y,1),rotate(x,1);
                    else
                        rotate(x,0),rotate(x,1);
                }
                else
                {
                    if(node[y].ch[1]==x)
                        rotate(y,0),rotate(x,0);
                    else
                        rotate(x,1),rotate(x,0);
                }
            }
        }
        push_up(x);
        if(!f) root=x;
    }
    int select(int k,int rt)
    {
        int tmp,t=root;
        for(;;)
        {
            push_down(t);
            int l=node[node[t].ch[0]].size;
            if(k>l && k<=l+node[t].w) break;
            if(k<=l)
                t=node[t].ch[0];
            else
                k-=(l+node[t].w),t=node[t].ch[1];
        }
        splay(t,rt);
        return t;
    }
    void split(int l,int r,int &s2)
    {
        select(l,0);
        select(r+2,root);
        int tmp=node[node[root].ch[1]].ch[0];
        node[node[root].ch[1]].ch[0]=0;
        push_up(node[root].ch[1]);
        push_up(root);
        s2=tmp;
    }
    void reverse(int l,int r)
    {
        select(l,0);
        select(r+2,root);
        node[node[node[root].ch[1]].ch[0]].col^=1;
    }
    void push_down(int rt)
    {
        if(rt && node[rt].col)
        {
            swap(node[rt].ch[0],node[rt].ch[1]);
            int l=node[rt].ch[0];
            int r=node[rt].ch[1];
            node[l].col^=1;
            node[r].col^=1;
            node[rt].col=0;
        }
    }
    void push_up(int rt)
    {
        if(!rt)return;
        int l=node[rt].ch[0];
        int r=node[rt].ch[1];
        int ret=node[rt].w;
        if(l) ret+=node[l].size;
        if(r) ret+=node[r].size;
        node[rt].size=ret;
    }
    void del(int p)
    {
        if(!p) return;
        del(node[p].ch[0]);
        del(node[p].ch[1]);
        delnode(p);
    }
    int build(int l,int r,int f)
    {

        if(l>r) return 0;
        int m=(l+r)>>1;
        int p=newnode(m);
        node[p].f=f;
        node[p].ch[0]=build(l,m-1,p);
        node[p].ch[1]=build(m+1,r,p);
        push_up(p);
        return p;
    }
    int getmin(int p)
    {
        push_down(p);
        while(node[p].ch[0])
        {
            p=node[p].ch[0];
            push_down(p);
        }
        return p;
    }
    void cut(int a,int b,int c)
    {
        spt tmp;
        split(a,b,tmp.root);
        select(c+1,0);
        c=getmin(node[root].ch[1]);
        splay(c,root);
        node[node[root].ch[1]].ch[0]=tmp.root;
        node[tmp.root].f=c;
        push_up(node[root].ch[1]);
        push_up(root);
    }
};

spt s1;
int n,m,cnt;
char s[20];

void solve(int p)
{
    if(!p) return;
    s1.push_down(p);
    solve(node[p].ch[0]);
    if(node[p].key!=0 && node[p].key!=n+1)
    {
        cnt++;
        printf("%d%s",node[p].key,cnt!=n?" ":"\n");
    }
    solve(node[p].ch[1]);
}

void prepare()
{
    s1.clear();
    s1.root=newnode(0);
    node[s1.root].ch[1]=newnode(n+1);
    node[node[s1.root].ch[1]].f=s1.root;
    node[node[s1.root].ch[1]].ch[0]=s1.build(1,n,node[s1.root].ch[1]);
    s1.push_up(node[s1.root].ch[1]);
    s1.push_up(s1.root);
}

int main()
{
    int a,b,c;
    init();
    while(~scanf("%d%d",&n,&m))
    {
        if(n==-1 && m==-1) break;
        prepare();
        for(int i=0;i<m;i++)
        {
            scanf("%s",s);
            if(strcmp(s,"FLIP")==0)
            {
                scanf("%d%d",&a,&b);
                s1.reverse(a,b);
            }
            else
            {
                scanf("%d%d%d",&a,&b,&c);
                s1.cut(a,b,c);
            }
        }
        cnt=0;
        solve(s1.root);
        s1.del(s1.root);
    }
    return 0;
}


 

spaly区间翻转分裂,合并!UVA11922,UVA11996也是个不错的spaly #include #include #include using namespace std; struct Node { Node *ch[2]; int s,v,flip; int cmp(int k) { int d=k-ch[0]->s; if(d==1) return -1; return d<=0?0:1; 阅读详情

相关推荐

HDU3487】【splay分裂合并】Play with Chain

Problem Description YaoYao is fond of playing his chains. He has a chain containing n diamonds on it. Diamonds are numbered from 1 to n.At first, the diamonds on the chain is a sequence: 1, 2, 3...

Gregory99174的博客 229

HDU 3487 Play with Chain

人生第一个splay题。 区间分裂区间合并还有区间翻转都是比较裸的板子 一个区间分裂成三个区间还是写一个两两分裂的函数比较好写( 区间合并也是 感觉其他也没有什么要针对这个题说的 只要splay写好了就能过 以及代码如下 #include using namespace std; #define l ch[0] #define r ch[1] struct no

lambda QAQ 480

hdu3487 Play with Chain (Splay)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3487 题意:给定一个长度为n(n 分析:Splay~ 对于操作1,是很直接的伸展树的操作。下面摘自kuangbin的文章: 3、伸展树区间操作 在实际应用中,伸展树的中序遍历即为我们维护的数列,这就引出一个问题,怎么在伸展树中表示某个区间?比如我们要提取区间[a,b],那么我们将a前

w20810的专栏 488

HDU-3487 Play with Chain Splay tee区间反转,移动

  题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3487   对于一个数列有两种操作:1.CUT a b c,先取出a-b区间的数,然后把它们放在取出后的第c个数后面。2.FLIP a b,把区间a-b的数反转。对于第一个操作,进行两次区间移动,第a-1个数Splay到根节点,b+1个数Splay到root的右儿子,ch[ch[root][1]]...

weixin_30920091的博客 126

NOI2004 郁闷的出纳员 SPLAY

郁闷的出纳员。我比他还郁闷,谢了将近两天,终于把第一到SPLAY写完了,之前一直用的treap但觉得splay的功能强大,有必要学一下。当然,当treap足够解决的时候还是用treap比较好,毕竟代码量要少点,不容易出错。 splay能够很好的对区间进行处理。 刚开始各种纠结,打算一个一个的删除,但由于判断加进了push_down 函数,程序直接爆掉,后来发现根本不能这么操作,因为这样会让程序

1707

POJ2352 Stars 树状数组

树状数组。因为Y坐标已经有序,所以直接统计当前star输入后,其x坐标左侧的星星数量(前面输入的star一定比后面的y坐标小。)然后+1即可,注意x坐标要左移1。因为数据存在x=0的情况。 罪过放松了好多天。 Stars Time Limit: 1000MS   Memory Limit: 65536K Total Submissio

1317

POJ2155 Matrix 树状数组

二维的树状数组,解题思想详见《浅谈信息学竞赛中的“0”和“1”》这篇论文,我上传了一份 http://download.csdn.net/detail/lenleaves/4548401 。很经典的题目,很经典的思想。 Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 128

1309

BZOJ2631 tree 动态树

注意用unsigned int ,一开始用long long我的动态树直接被卡出翔。 这道题目与AHOI2009的拿到线段树维护延迟标记的方法是一样的,先乘再加 ,这道题目要维护子树的大小(用来加)。 操作 + u v c   区间u到v之间的路径都加c * u v c 区间u到v之间的路径都乘c - u1 v1 u2 v2 断开(u1,v1)连上(u2,v2) / u v 查询

1299

SDOI2011 染色 动态树

动态树,将区间染色,统计区间内颜色的段数。 这种区间统计题目,注意下推的时候要连续下推2层,与维修数列相同。 2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 1041  Solved: 422 [Submit][Status][Discuss] Description

1276

HDU3966 Aragorn's Story 树链剖分

裸地不能在裸的树链剖分了,col忘记清空,狂wa一小时。 本来想学LINK CUT TREE的,考试接踵,做题状态全无。== ==暂时顺延了 Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis

1197

POJ3253 Fence Repair stl+哈夫曼树

用顶小堆计算哈夫曼树的总权。 每次取出最小的两个顶点,权值相加,然后加入答案中,然后在讲合并和后的值加入堆中,直到只有一个节点是结束。 因为这种方法,一个叶子节点会被重复加他的深度次 Fence Repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 18840   A

1133

HDU4010 Query on The Trees 动态树

我只能说忽略了细节啊。 大家第一次写动态树的时候注意了。由于ACCESS的时候改变一个节点的左右儿子的值,但是但是你左右儿子的父节点的值时不会被修改的!!!!!!! 所以rotate这么写的人太注意了,一个else WA了一整天啊啊 if(node[y].f) { if(node[node[y].f].ch[0]==y) node[no

1087

HNOI2010 Bounce 弹飞绵羊 动态树

如果i能弹到j,则将i和j相连 i的弹力系数修改后,先断开原来的边,然后与新的边连接即可。 统计每一个子树的节点数。输出的时候-1; 2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 2567  Solved: 1382 [Submit][Status][Discuss]

1064

UVA11997 K Smallest Sums 多路归并(优先队列)

//多路归并问题 //把k个有序表合并成一个有序表。 //大于2是两两归并 //本题只要求出k个最小的,所以可以限制上限 //k个整数数组,每个数组包含k个数,在每个数组中 //去一个数加起来,得到K^K个和 //求这些和中的最小的k个值 K Smallest Sums You're given k arrays, each array has k integers

1056

UVA 11922 Permutation Transformer SPLAY 区间分裂,曲间插入

SPLAY水题。和HDU上那题一样的操作。。。。复习一下SPLAY,,,UVA提交返回结果好慢。。。等了5分多钟啊。。。。在UVA上面Verdict里是空着的。。。不知道为什么。但在虚拟OJ上面提交过了,返回结果巨慢。。一直processing太奇怪了   题目地址:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Item

1044

HDU1890 Robotic Sort SPLAY

这道题目需要伸展树的区间翻转操作,另外这道题我完成了我的SPLAY的删除节点的操作,由于伸展树的操作特点,删除某个节点的步骤是将该节点旋转到root然后再删除,也就是啊说,我们只要写个删除根节点的函数即可。 另外注意push_down的位置。 感想:伸展树真的很漂亮,这些操作都很神奇   解法: 题目意思是我们要将所有试管从低到高排序,刚开始试管是无序的。因此需要一个机械手臂从低到高抓取

1040

LA3644 X-Plosives 并查集(维护连通分量,判断有无环)

一个元素当做一个节点,一个物品由两个节点之间的一条边(因为一个物品由2个元素组成),让元素相连产生一个环的时候会产生危险 现在给我们很多个物品,要我们输出剔除多少个物品,能够保证安全 做法:用并查集维护一个图的连通分量几个,每次得到化合物(x,y)时,检查x和y是否在一个集合中,如果是则需要拒绝当前化合物,(因为x,y在一个连通分量中,此时图尚不存在环,可以说是一棵树,但当边x-y加入到该连通

1005

POJ3580 SuperMemo SPLAY 各种操作。。。。

这道题目需要实现SPLAY的各种操作。。。。。码了大半天,幸亏1A,否则今晚是不用睡觉了。。。。。 一共六个操作 1:删除第K个节点 2:在第k个节点后面插入一个数 3:将区间[l,r]翻转 4:将区间[l,r]每个节点加上一个数 5:查询区间[l,r]的最小值 以上五种操作都很基本,只不过维护两个lazy标记而已,push_down的时候多做一步而已,关键是下面那个操作。 6:在

1002
上一篇: HDU1890 Robotic Sort SPLAY
下一篇: POJ3905 Perfect Election 2-SAT
Albafica
博客等级 码龄15年 98粉丝 359原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值