题目大意

给定一个长度小于等于kk的字符串和qq,表示现在有qq个操作,每个操作给定两个参数li,ril_i,r_i表示把现在的字符串第lil_i到rir_i把其中编号为奇数的按顺序写下来,再在后面把编号为偶数的按顺序写下来,最后把写出的新字符串加在区间后面。
一下为两个例子:
1、s1s2s3s4s5s6s7,li=3ri=5。操作后变成:s1s2s3s4s5s3s5s4s6s71、s_1s_2s_3s_4s_5s_6s_7 , l_i=3 r_i=5 。操作后变成:s_1s_2s_3s_4s_5s_3s_5s_4s_6s_7
2、s1s2s3s4s5s6s7,li=4ri=7。操作后变成:s1s2s3s4s5s6s7s5s7s4s62、s_1s_2s_3s_4s_5s_6s_7, l_i=4 r_i=7。操作后变成: s_1s_2s_3s_4s_5s_6s_7s_5s_7s_4s_6
给定每组li,ril_i,r_i要求输出操作完的字符串的前kk位是什么。

q≤5000q\leq 5000
k≤3000000k \leq 3000000
li,ri≤109l_i,r_i \leq 10^9

解题思路

首先一个显然的性质,对于当前的字符串,在第kk个·字符后面的肯定是没有用的。考虑题目给定的操作,由于字符串是动态变换的,所以很难维护字符串的信息。那么我们考虑对于操作,从后往前做,那么就能保证每确定一个位置,这个位置上的字符就不会变。

照着这个思路我们只需每次找出字符串的第lil_i个位置和第li+ril_i+r_i个位置,分别表示当前需要复制区间的其实位置以及复制后区间的起始位置。我们只需把后面的区间上的位置打上与前面某个位置相等的标记。然后由于这个区间已经确定下来,所以把这段区间标记为“删除”,并且在我们下次找区间第lil_i个位置时就不能算上“删除”的位置。

现在就又遇到了两个问题,以一个是怎么找到第lil_i个未被打上“删除”的位置,以及上某个位置下一个未被打上“删除”的位置。我们观察一下数据范围,我们发现只有50005000个修改操作,并且一个操作肯定是连续的一段区间(就算不连续,中间的位置也一定是被打上删除标记的)。那么我们可以用并查集把相邻的“删除”位置并到一起,并记录下它覆盖的区间。那么找位置时可用的就是两个被“删除”的区间有有多少个位置,只需O(n)O(n)扫一遍就可以知道位置。对于第二个问题也一样,由于我们把相邻的“删除”的区间并在了一起,所以加入下一个位置是被“删除”了的,就只需跳到这个区间右边界+1就可以了。

最后输出时扫一遍就可以了。

程序

//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int MAXN = 1e5 + 5, MAXM = 5e3 + 5, MAXK = 3e6 + 5;struct Node {int l, r;Node(int a, int b) {l = a, r = b;}Node() {}
};bool flag[MAXK];
Node D[MAXM], Coor[MAXK];
char S[MAXK], T[MAXK];
int n, k, len, top, l[MAXM], r[MAXM], ord[MAXK], lst[MAXK], deep[MAXK];int Get(int s) {int get = 0;for (int j = 2; j <= top; j ++) {if (get + D[j].l - 1 - D[j - 1].r >= s) {return D[j - 1].r + s - get;break;} else get += D[j].l - 1 - D[j - 1].r;}return 0;
}int Find(int x) {if (ord[x] == x) return x;ord[x] = Find(ord[x]);return ord[x];
}void Merge(int x, int y) {int fx = Find(x), fy = Find(y);if (fx == fy) return;if (deep[fx] > deep[fy]) swap(fx, fy);ord[fx] = fy;Coor[fy] = Node(min(Coor[fx].l, Coor[fy].l), max(Coor[fx].r, Coor[fy].r));if (deep[fx] == deep[fy]) deep[fy] ++;
}void Maketag(int p) {flag[p] = 1;if (flag[p - 1]) Merge(p, p - 1);if (flag[p + 1]) Merge(p, p + 1);
}int Next(int s) {int p = s + 1;while (p <= k && flag[p]) p = Coor[Find(p)].r + 1;if (p > k || flag[p]) return 0;return p;
}int main() {scanf("%s", S + 1);len = strlen(S + 1);scanf("%d%d", &k, &n);for (int i = 1; i <= n; i ++) scanf("%d%d", &l[i], &r[i]);D[1] = Node(0, 0), D[2] = Node(k + 1, k + 1);top = 2;for (int i = 1; i <= k; i ++) ord[i] = lst[i] = i, Coor[i] = Node(i, i);for (int i = n; i; i --) {int s1 = Get(l[i]), s2 = Get(r[i] + 1), len = r[i] - l[i] + 1;if (s2 == 0) continue;int cnt = 1, p = ((l[i] & 1) || len == 1) ? s1 : Next(s1), t = s2, Last = 0;for (; ; cnt ++) {Maketag(t);lst[t] = p;Last = max(Last, t);if (cnt == len) break;int tmp = Next(t);if (!tmp) break;t = tmp;if (cnt == (len + (l[i] & 1)) / 2) p = (l[i] & 1) ? Next(s1) : s1; else p = Next(Next(p));}int del = 0;for (int i = 1; i <= top; i ++) {p = i - del;D[p] = D[i];if (Find(D[p].r) == Find(s2)) del ++;}top -= del;D[++ top] = Coor[Find(s2)], p = top;for (; p > 1 && D[p].l < D[p - 1].l; p --) swap(D[p], D[p - 1]);}int get = 0;for (int i = 1; i <= k; i ++) {if (lst[i] == i) {get ++;T[i] = S[get];} else T[i] = T[lst[i]];printf("%c", T[i]);}printf("\n");
}

JZOJ4708. 【NOIP2016提高A组模拟8.20】奇洛金卡达 倒着做的思想+并查集维护相关推荐

  1. JZOJ 100024. 【NOIP2016提高A组模拟7.6】数球

    Description 小A有n个球,编号分别为1到n,小A每次都会从n个球中取出若干个球,至少取一个,至多取n个,每次取完再放回去,需要满足以下两个条件. 每次取出的球的个数两两不同. 每次取出的球 ...

  2. 【NOIP2016提高A组模拟9.9】闭门造车

    题目 自从htn体验了一把飙车的快感,他就下定决心要闭门造车!但是他两手空空怎么造得出车来呢?无奈的他只好来到了汽车零部件商店. 一走进商店,玲琅满目的各式零件看得htn眼花缭乱.但是他很快便反应过来 ...

  3. [JZOJ4788] 【NOIP2016提高A组模拟9.17】序列

    题目 描述 题目大意 一个序列,每次可以使一段区间内的所有数加一(模四). 问最少的操作次数. 思考历程 一看这题目,诶,这不就是那道叫密码锁的题目吗? 然后随便打一打,样例过了,就再也没有思考这一题 ...

  4. JZOJ 4726. 【NOIP2016提高A组模拟8.22】种花

    Description 经过三十多个小时的长途跋涉,小Z和小D终于到了NOI现场--南山南中学.一进校园,小D就被花所吸引了(不要问我为什么),遍和一旁的种花园丁交(J)流(L)了起来. 他发现花的摆 ...

  5. JZOJ 4676. 【NOIP2016提高A组模拟7.21】模板串

    Description 科学家温斯顿从数据库中找到了一串相当长的字符串. 他正试图用一个模板串来重构这个字符串. 他可以将模板串复制多份,通过合适的方式拼接起来,使得最终的串与原串一致. 如果两个模板 ...

  6. JZOJ 4675. 【NOIP2016提高A组模拟7.21】Double-row

    Description 科学家温斯顿在一张超长的白纸上写下了两行数,每一行数有N个. 但他写完后觉得看起来有点不和谐.他希望重新编排,使得每一行数中没有相同的数. 他每次可以调换同一列的两个数. 请帮 ...

  7. JZOJ 4786. 【NOIP2016提高A组模拟9.17】小a的强迫症

    Description Input Sample Input 3 2 2 1 Output Sample Output 3 样例解释: Data Constraint Solution 首先,我们设之 ...

  8. 【JZOJ4819】【NOIP2016提高A组模拟10.15】算循环

    题目描述 输入 输出 样例输入 167 198 样例输出 906462341 数据范围 解法 令f(n)=∑ni=1i,g(n)=∑ni=1i2 易得ans=∑ni=1∑mj=1f(n−i+1)∗f( ...

  9. 【NOIP2016提高A组模拟10.15】打膈膜

    题目 分析 贪心, 先将怪物按生命值从小到大排序(显然按这个顺序打是最优的) 枚举可以发对少次群体攻击, 首先将所有的群体攻击发出去, 然后一个一个怪物打,当当前怪物生命值大于2,如果还有魔法值就放重 ...

最新文章

  1. Spring Cloud、K8S、Netflix OSS三者啥关系???
  2. 百度股价接连暴涨的背后,看Apollo的2020
  3. 机器学习(MACHINE LEARNING)MATLAB求解利润最大化问题【线性规划】
  4. 用c语言 简单实现JAVA里面的ArryList 功能,实现内存自动扩展
  5. 人脸扫描建模_人脸识别智能锁安全吗?
  6. Access保留关键字
  7. No transaction aspect-managed TransactionStatus in scope
  8. 肝!用 Highcharts 绘制饼图,也很强大
  9. response 流和写能一起吗_余甘果蜂蜜能一起吃吗?余甘果泡蜂蜜有什么功效?
  10. 推荐WCF的一系列录像
  11. 学习 | Spring Cloud Config 从入门到精通
  12. maven 安装后变成 mvn 不是内部命令解决方法
  13. c++指针各种用法小结
  14. 易基因 | 国自然选题——易基因RNA甲基化测序技术(m6A m5C)正热门
  15. Biotion-PEG-Mal,Maleimide-PEG-Biotin,生物素聚乙二醇马来酰亚胺分子量
  16. python怎么重复画圆_重画圆Python
  17. 后台接收前台传来的图片并保存在本地
  18. 必刷|2022年贵州最新八大员之(安全员)模拟题库及答案
  19. 华为数通笔记-ISIS基础
  20. 项目review会议的步骤_8个步骤,使您的下一次会议更有效率

热门文章

  1. 微信小程序this.data赋值时,页面视图层没有同步更新
  2. 51自学网AutoCAD2014室内设计 AutoCAD2009施工图教程 CAD布局及规范作图教程 室内手绘入门教程...
  3. 笔记:对余额宝等货币基金的理解
  4. ABBYYFineReader15免费电脑pdf文档文字识别软件
  5. 用这些软件重装windows也太好用了吧(懒人一键安装windows软件推荐)
  6. 命运歌姬服务器停服维护中,命运歌姬2月27日更新什么? 2月27日双端维护内容公告...
  7. NOC C++ 全国中小学信息技术创新与实践大赛(NOC):软件创意编程赛道
  8. Stata:动态面板数据模型与xtabond2应用
  9. js自动触发点击事件
  10. https://www.cnblogs.com/lyhabc/archive/2013/06/12/3133273.html?tdsourcetag=s_pcqq_aiomsg