SGU 187 - Twist and whirl -- want to cheat

原题地址:http://acm.sgu.ru/problem.php?contest=0&problem=187

太开心啦!!!!这道题从2013年开始困扰我!!今天晚上第四次下定决心把它写一写,之前写了三次(事实上是五个程序)都没有把它搞定,甚至无从查错……没想到今晚居然1A啦太激动了喵哈哈~我先去激动一会

题目大意:给定一个数字n,构建一个从1 ~ n的初始数列,给出 m 个操作,每个操作对应两个数字 x 和 y 每次将当前序列中的第 x 位到第 y 位翻转,输出最终的序列

数据范围和限制:1<=N<=130000, 1<=M<=2000, 时间限制0.25s, 内存限制 4M(这……)

题目分析:这题貌似是改过数据范围或者内存限制,反正网上很多大牛直接建了一棵 n 的节点的伸展树,然后进行区间翻转,但是现在的数据范围必然导致MLE。但是这并不意味着伸展树无计可施我们需要另寻它路。hockey传授的解法是这样的:将每个区间视为一个点( 记作[l, r] ),在需要对它的子区间 [i, j] 进行翻转操作时,我们将它拆成三个点 [l, i]、[i, j]、[j, r],然后在[i, j]上打上翻转标记……

一般地来讲就是这样:我们的Splay是由若干个区间组成的,当我们需要翻转区间[i, j]时,先查找出 i - 1 在当前树中的哪个区间上,然后将它拆成左右两个区间(约定我们拆分的左区间包含数i - 1)并记录左区间A,同样地,我们在树中查找 j 的位置并拆分,记录右区间B,将B旋转到根,再将A旋转为B的左儿子,则A的右子树就是待操作的区间,对其进行标记即可。

下面贴出我的代码,尽可能使注释详细

  1 //date 20140119
  2 #include <cstdio>
  3 #include <cstring>
  4 
  5 inline int getint() //读入优化
  6 {
  7     int ans (0); char w = getchar();
  8     while('0' > w || '9' < w)w = getchar();
  9     while('0' <= w && w <= '9')
 10     {
 11         ans = ans * 10 + w - '0';
 12         w = getchar();
 13     }
 14     return ans;
 15 }
 16 
 17 inline int min(int a, int b){return a < b ? a : b;}
 18 inline int max(int a, int b){return a > b ? a : b;}
 19 
 20 int n, m;
 21 struct SPlay
 22 {
 23     struct node
 24     {
 25         int l, r, rev, revit, size; // l、r为区间左右端点,rev标记以当前节点为根的整棵子树是否被翻转,revit标记当前节点所代表的区间是否被翻转
 26         node *s[2], *p;
 27         int sum(){return r - l + 1;}
 28         int getlr(){return p->s[1] == this;}
 29         node(int ll, int rr){l = ll; r = rr; s[0] = s[1] = p = 0; rev = revit = 0; size = sum();}
 30         node *link(int w, node *p){s[w] = p; if(p)p->p = this; return this;}
 31         void update(){size = (s[0] ? s[0]->size : 0) + (s[1] ? s[1]->size : 0) + sum();}
 32         void pushdown()//旋转标记下放
 33         {
 34             if(rev)
 35             {
 36                 node *q = s[0]; s[0] = s[1]; s[1] = q;
 37                 if(s[0])s[0]->rev ^= 1;
 38                 if(s[1])s[1]->rev ^= 1;
 39                 revit ^= 1;
 40                 rev = 0;
 41             }
 42         }
 43     }*root;
 44     
 45     void rot(node *p)
 46     {
 47         node *q = p->p->p;
 48         p->getlr() ? p->link(0, p->p->link(1, p->s[0])) : p->link(1, p->p->link(0, p->s[1]));
 49         p->p->update();
 50         if(q)q->link(q->s[1] == p->p, p);else{root = p; p->p = 0;}
 51     }
 52     
 53     void splay(node *p, node *tar)
 54     {
 55         while(p->p != tar && p->p->p != tar)
 56             p->getlr() == p->p->getlr() ? (rot(p->p), rot(p)) : (rot(p), rot(p));
 57         if(p->p != tar)rot(p);
 58         p->update();
 59     }
 60     
 61     void preset(int l, int r){root = new node(l, r);}
 62     //以上是伸展树的基本操作,如有不熟悉可以参照我博客之前一篇介绍伸展树的文章
 63     int findKth(int k)//寻找当前序列的第k个数所在的区间,并将其旋转到根,返回值pos是指需要将找到的区间从该区间的第pos个数拆成两个区间
 64     {
 65         node *p = root;
 66         p->pushdown();
 67         while(!(((p->s[0] ? p->s[0]->size : 0) < k) && ((p->s[0] ? p->s[0]->size : 0) + p->sum() >= k)))//如果没有找到则继续找
 68         {
 69             if((p->s[0] ? p->s[0]->size : 0) >= k){p = p->s[0]; p->pushdown();}
 70             else{k -= (p->s[0] ? p->s[0]->size : 0) + p->sum(); p = p->s[1]; p->pushdown();}
 71         }
 72         k -= (p->s[0] ? p->s[0]->size : 0);//记录k在该区间中的实际位置,以便拆点
 73         splay(p, 0);
 74         return k;
 75     }
 76     
 77     void divide(node *p, int pos)//将节点p拆成两个节点,使拆解后的左区间包含恰好pos个数
 78     {
 79         p->pushdown();
 80         if(p->sum() == pos)return;//如果不需要拆,则不拆
 81         node *q1, *q2;
 82         if(p->revit)
 83         {
 84             q1 = new node(p->r - pos + 1, p->r); q1->revit = 1;
 85             q2 = new node(p->l, p->r - pos); q2->revit = 1;
 86         }
 87         else
 88         {
 89             q1 = new node(p->l, p->l + pos - 1);
 90             q2 = new node(p->l + pos, p->r);
 91         }
 92         q1->link(1, q2->link(1, p->s[1]));
 93         q1->link(0, p->s[0]);
 94         q2->update();
 95         q1->update();
 96         if(!p->p)root = q1;
 97         else p->p->link(p->getlr(), q1);
 98         delete p;
 99     }
100     
101     node *succ()//寻找当前根节点的后继,属于基础操作
102     {
103         root->pushdown();
104         node *q = root->s[1];
105         q->pushdown();
106         while(q->s[0]){q = q->s[0]; q->pushdown();}
107         splay(q, 0);
108         return q;
109     }
110     void deal(int a, int b)//翻转区间[a,b]
111     {
112         int i = findKth(a - 1);//找到当前区间的前驱
113         divide(root, i);
114         node *p = root;
115         int j = findKth(b);//找到当前区间的后继
116         divide(root, j);
117         node *q = succ();
118         splay(p, q);
119         p->s[1]->rev ^= 1;//进行标记
120         p->s[1]->pushdown();
121     }
122     
123     void print(node *p)//以下是一个中根便利进行输出
124     {
125         p->pushdown();
126         if(p->s[0])print(p->s[0]);
127         if(p->revit)for(int i = min(p->r, n); i >= max(1, p->l); --i)printf("%d ", i);
128         else for(int i = max(1, p->l); i <= min(p->r, n); ++i)printf("%d ", i);
129         if(p->s[1])print(p->s[1]);
130     }
131     
132     void print()
133     {
134         print(root);
135         printf("\n");
136     }
137 }S;
138 
139 int main()
140 {
141     n = getint(); m = getint();
142     S.preset(0, n + 1);//0和n + 1是哨兵节点,防止越界
143 
144     int x, y;
145     for(int i = 1; i <= m; ++i)
146     {
147         x = getint(); y = getint();
148         S.deal(x + 1, y + 1);//由于0的存在,第x个数实际上是第x + 1个数
149     }    
150     S.print();
151     return 0;
152 }

小注:理解算法之后这道题就是锻炼编程能力了,希望能给在这道题卡住的同学们一点帮助吧

转载于:https://www.cnblogs.com/w007878/p/3526297.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/493505.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

KNN实现CIFAR-10数据集识别

cs231n链接&#xff1a;http://cs231n.github.io/linear-classify/&#xff0c; 训练集链接&#xff1a;https://download.csdn.net/download/fanzonghao/10592049 KNN缺点&#xff1a;每个测试样本都要循环一遍训练样本。 该数据集由5个data_batch和一个test_batch构成&…

近期苹果、Facebook等科技巨头股价缘何不断下跌?

来源&#xff1a;资本实验室近期&#xff0c;FAANG(Facebook、亚马逊、苹果、Netflix、谷歌)等科技巨头股价都出现了不同程度的下跌&#xff0c;而美国科技股整体的持续大跌&#xff0c;更是引发了全球股市振荡。其中&#xff0c;亚马逊在今年9月初达曾达到1万亿美元市值&#…

ZOJ 3300 Mahjong DFS暴力解决。。

ZJU 3300&#xff1a; 题目描述 就看成1—9的数字&#xff0c;DFS暴力搜索下就过了。。。。。要求输入13 个数字&#xff0c;声明个数组记录数字的个数&#xff0c;DFS 里各种回溯&#xff1b;#include<stdio.h> #include<string.h> int p[12],flag; int dfs(int x…

概率论基础知识各种分布

离散分布&#xff1a;伯努力分布&#xff0c;二项分布&#xff0c;possion分布 一&#xff0c;伯努力分布 #执硬币 x_arrnp.array([0,1]) #x为1的概率 p0.7 #0 1分布 #由PMF生成对应的概率 离散事件 pr_arrstats.bernoulli.pmf(x_arr,p) plt.plot(x_arr,pr_arr,markero,lines…

AI 芯片和传统芯片的区别

来源&#xff1a;内容来自「知乎汪鹏 」所谓的AI芯片&#xff0c;一般是指针对AI算法的ASIC&#xff08;专用芯片&#xff09;。传统的CPU、GPU都可以拿来执行AI算法&#xff0c;但是速度慢&#xff0c;性能低&#xff0c;无法实际商用。比如&#xff0c;自动驾驶需要识别道路行…

三层神经网络实现手写数字的识别(基于tensorflow)

数据集链接&#xff1a;https://download.csdn.net/download/fanzonghao/10598333 from tensorflow.examples.tutorials.mnist import input_data mnist input_data.read_data_sets("./mnist/", one_hotTrue)import tensorflow as tf# Parameters learning_rate 0…

鼠标终将消失,未来我们有哪些人机交互方式?

来源&#xff1a;资本实验室在人类发明史上&#xff0c;诞生了无数的英雄。他们的发明往往从一项前沿技术到家喻户晓、无处不在&#xff0c;但他们自己却又鲜为人知&#xff0c;美国发明家道格拉斯恩格尔巴特就是其中的代表。20世纪60年代&#xff0c;道格拉斯恩格尔巴特发明了…

两层卷积网络实现手写数字的识别(基于tensorflow)

可和这篇文章对比&#xff1a;https://blog.csdn.net/fanzonghao/article/details/81603367 # coding: utf-8 # ## MNIST数据集from __future__ import division, print_function, absolute_importimport tensorflow as tf# Import MNIST data&#xff0c;MNIST数据集导入 fro…

光波导总结资料

1、写出光波导中的麦克斯韦方程&#xff0c;并把光场分解为纵向分量与横向分量&#xff0c;求出混合模式HE与EH模式的横向电场强度与横向磁场强度的点积&#xff08;用纵向分量表示&#xff09;&#xff08;需要有推导过程&#xff09; 解&#xff1a;在线性、各向同性且时不变…

德国再出颠覆性发明,这次要安排我们的快递

来源&#xff1a;最黑科技摘要&#xff1a;如果用一句话来形容德国的工业设计&#xff0c;我能想到的就是&#xff1a;“母牛坐电锯——锯牛逼"&#xff0c;小编已经不止一次把它吹得五光十色斗转星移~但你可能不知道&#xff0c;这个工业强国在2013年还提出了一个著名的发…

跟我一起写 Makefile

跟我一起写 Makefile【转】 陈皓 概述—— 什么是makefile&#xff1f;或许很多Winodws的程序员都不知道这个东西&#xff0c;因为那些Windows的IDE都为你做了这个工作&#xff0c;但我觉得要作一个好的和professional的程序员&#xff0c;makefile还是要懂。这就好像现在有这么…

C++中用frugally-deep调用keras的模型并进行预测

1、背景 Python语言中的Keras库搭建深度学习模型非常便捷&#xff0c;但有时需要在 C 中调用训练好的模型&#xff0c;得到测试集的结果。比如将模型部署于FPGA&#xff0c;中间的一个步骤则需要用C构建模型。但 Keras库没有提供 C API&#xff0c;其中一种解决方法是使用 Ten…

简单的线性回归实现模型的存储和读取

和这篇文章对比https://blog.csdn.net/fanzonghao/article/details/81023730 不希望重复定义图上的运算&#xff0c;也就是在模型恢复过程中&#xff0c;不想sess.run(init)首先看路径 lineRegulation_model.py定义线性回归类&#xff1a; import tensorflow as tf "&qu…

MIT重新发明飞机:无需燃料,每秒万米喷射带你上天 | Nature封面

来源&#xff1a;量子位这不是科幻小说&#xff0c;离子引擎飞机真的被造出来了&#xff01;“曲率引擎”、“离子引擎”等等激动人心的科幻名词&#xff0c;正在走进现实。最近MIT又重新发明了飞机&#xff0c;实验成果登上了《自然》杂志封面。这架飞机翼展5米&#xff0c;总…

union intersect minus

Intersect和Minus的操作和Union基本一致&#xff0c;这里一起总结一下&#xff1a; Union&#xff0c;对两个结果集进行并集操作&#xff0c;不包括重复行&#xff0c;同时进行默认规则的排序&#xff1b; Union All&#xff0c;对两个结果集进行并集操作&#xff0c;包括重复…

unet实现区域分割

https://github.com/zonghaofan/pig-seg/tree/master/disk_segmentation 网络架构&#xff1a; # coding:utf-8 import tensorflow as tf import cv2 import numpy as np import matplotlib.pyplot as pltimg cv2.imread(./data/test.png)# cv2.imshow(1.jpg,img) # cv2.wait…

数字图像处理 实验一 图像的基本运算

实验一 图像的基本运算 一、实验目的 &#xff08;1&#xff09;掌握点运算和代数运算的算法实现和概念 &#xff08;2&#xff09;掌握和几何运算的算法实现和概念 &#xff08;2&#xff09;掌握灰度变换和几何变换的基本方法 &#xff08;3&#xff09;理解图像灰度直方图的…

MongoDB 语法陷阱(转自51CTO)

1. 哈希对象中key的顺序 比如&#xff0c;你要存储一个简单的文字对象&#xff1a;: > db.books.insert({ title: "Woe from Wit", meta: { author: "A. Griboyedov", year: 1823 } }); 太棒了&#xff01;现在我们有了一条书籍记录。再比如&#xff0c…

2018世界人工智能蓝皮书:看中国到底有多强!【附下载】| 智东西内参

来源&#xff1a;智东西人工智能是引领未来的战略性高科技&#xff0c;作为新一轮产业变革的核心驱动力&#xff0c;催生新技术、新产品、新产业、新模式&#xff0c;引发经济结构重大变革&#xff0c;深刻改变人类生产生活方式和思维模式&#xff0c;实现社会生产力的整体跃升…

tensorflow(GPU)使用

一&#xff0c;直接指定GPU: tf.ConfigProto一般用在创建session的时候。用来对session进行参数配置 with tf.Session(config tf.ConfigProto(...),...) #tf.ConfigProto()的参数 log_device_placementTrue : 是否打印设备分配日志 allow_soft_placementTrue &#xff1a; 如…