前言

题目链接:洛谷Hydro & bzoj

题意简述

yzh 喜欢写 DS 题!你要维护一个环:

  1. 顺时针移动 \(k\) 位;
  2. 翻转 \(2 \sim n\);
  3. 交换 \(i\) 与 \(j\);
  4. 区间覆盖;
  5. 查询整个环有几个颜色段;
  6. 查询 \(i \sim j\) 有几个颜色段。

题目分析

平衡树板子啊,代码很好写,\(273\) 行。但是为什么不使用线段树呢?

发现,顺时针移位,原本该连续的区间也还在一块(这里指的是环上,在序列上可能一个在首一个在尾,但这对分析问题并不重要)。所以遇到移位操作,只用记录一个偏移量,查询的时候对下表进行相应处理即可。同理,翻转操作也不必真的进行翻转,只用记一个翻转标记,每次让它异或 \(1\) 即可。我们可以轻松写出如下转换函数。

auto trans = [&mov, &flip] (int x) -> int {
if (flip) x = mov - x + 2;
else x = x - mov;
x = (x % n + n) % n;
return x ? x : n;
};

接下来考虑线段树如何实现。我们发现,问题变成了区间覆盖、单点查询颜色、区间查询颜色段数。很套路,在信息中记录左右端点的颜色以及区间内的颜色段数。合并的时候把两个自区间颜色段数相加,如果左边的右端点和右边的左端点颜色相同,再减去一次重复算的这一次。

struct Info {
int l, r, cnt;
friend Info operator + (const Info& a, const Info& b) {
return { a.l, b.r, a.cnt + b.cnt - (a.r == b.l) };
}
};

剩下的板子不展开。

代码

// #pragma GCC optimize(3)
// #pragma GCC optimize("Ofast", "inline", "-ffast-math")
// #pragma GCC target("avx", "sse2", "sse3", "sse4", "mmx")
#include <iostream>
#include <cstdio>
#define debug(a) cerr << "Line: " << __LINE__ << " " << #a << endl
#define print(a) cerr << #a << "=" << (a) << endl
#define file(a) freopen(#a".in", "r", stdin), freopen(#a".out", "w", stdout)
#define main Main(); signed main() { return ios::sync_with_stdio(0), cin.tie(0), Main(); } signed Main
using namespace std; int n, m, col[500010]; struct Segment_Tree {
#define lson (idx << 1 )
#define rson (idx << 1 | 1) struct Info {
int l, r, cnt;
friend Info operator + (const Info& a, const Info& b) {
if (a.l == -1) return b;
if (b.l == -1) return a;
return { a.l, b.r, a.cnt + b.cnt - (a.r == b.l) };
}
}; struct node {
int l, r;
int tag;
Info info;
} tree[500010 << 2]; void build(int idx, int l, int r) {
tree[idx] = {l, r, -1, {0, 0, 0}};
if (l == r) return tree[idx].info = {col[l], col[r], 1}, void();
int mid = (l + r) >> 1;
build(lson, l, mid);
build(rson, mid + 1, r);
tree[idx].info = tree[lson].info + tree[rson].info;
} void pushtag(int idx, int tag) {
tree[idx].tag = tag;
tree[idx].info = {tag, tag, 1};
} void pushdown(int idx) {
if (tree[idx].tag == -1) return;
pushtag(lson, tree[idx].tag);
pushtag(rson, tree[idx].tag);
tree[idx].tag = -1;
} void modify(int idx, int l, int r, int tag) {
if (tree[idx].l > r || tree[idx].r < l) return;
if (l <= tree[idx].l && tree[idx].r <= r) return pushtag(idx, tag);
pushdown(idx);
modify(lson, l, r, tag);
modify(rson, l, r, tag);
tree[idx].info = tree[lson].info + tree[rson].info;
} Info query(int idx, int l, int r) {
if (tree[idx].l > r || tree[idx].r < l) return {-1, -1, 0};
if (l <= tree[idx].l && tree[idx].r <= r) return tree[idx].info;
pushdown(idx);
return query(lson, l, r) + query(rson, l, r);
} #undef lson
#undef rson
} yzh; #ifdef XuYueming
#define printf printf(">>> "), printf
#endif signed main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%d", &col[i]);
scanf("%d", &m), yzh.build(1, 1, n);
for (int i, j, c, k, mov = 0, flip = 0; m--; ) {
static char op[10];
static auto trans = [&mov, &flip] (int x) -> int {
if (flip) x = mov - x + 2;
else x = x - mov;
x = (x % n + n) % n;
return x ? x : n;
};
scanf("%s", op);
if (*op == 'R') {
scanf("%d", &k);
mov = (mov + k) % n;
} else if (*op == 'F') {
flip ^= 1, mov = (n - mov) % n;
} else if (*op == 'S') {
scanf("%d%d", &i, &j);
i = trans(i), j = trans(j);
int ci = yzh.query(1, i, i).l, cj = yzh.query(1, j, j).l;
yzh.modify(1, i, i, cj), yzh.modify(1, j, j, ci);
} else if (*op == 'P') {
scanf("%d%d%d", &i, &j, &c);
i = trans(i), j = trans(j);
if (flip) swap(i, j);
if (i <= j) {
yzh.modify(1, i, j, c);
} else {
yzh.modify(1, i, n, c);
yzh.modify(1, 1, j, c);
}
} else if (op[1] == '\0') {
printf("%d\n", max(1, yzh.tree[1].info.cnt - (yzh.tree[1].info.l == yzh.tree[1].info.r)));
} else {
scanf("%d%d", &i, &j);
i = trans(i), j = trans(j);
if (flip) swap(i, j);
if (i <= j) {
printf("%d\n", yzh.query(1, i, j).cnt);
} else {
printf("%d\n", (yzh.query(1, i, n) + yzh.query(1, 1, j)).cnt);
}
}
}
return 0;
}

后记 & 反思

没有敏锐地发现连续段在操作后还是连续的这一性质,导致没秒掉这道水题。

[NOI2007] 项链工厂 题解的更多相关文章

  1. BZOJ1493 [NOI2007]项链工厂

    未完待续... 终于改对了 热泪盈眶.jpg 错误原因:pushdown的时候没有判断是否有左右儿子,也没当x=0 return,于是出现一些奇怪的错误 #include<bits/stdc++ ...

  2. bzoj 1493: [NOI2007]项链工厂(线段树)

    1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 1256  Solved: 545[Submit][Status] ...

  3. 数据结构(Splay平衡树): [NOI2007] 项链工厂

    [NOI2007] 项链工厂 ★★★   输入文件:necklace.in   输出文件:necklace.out   简单对比 时间限制:4 s   内存限制:512 MB [问题描述] T公司是一 ...

  4. bzoj1493[NOI2007]项链工厂 线段树

    1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 1712  Solved: 723[Submit][Status] ...

  5. BZOJ_1493_[NOI2007]项链工厂_Splay

    BZOJ_1493_[NOI2007]项链工厂_Splay Description T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖.款式多样.价格适中,广受青年人的喜爱. 最近T公司打算 ...

  6. 1493: [NOI2007]项链工厂

    线段树. 真还就是个线段树.. 除去操作1,2的话,线段树很容易就处理了,问题在于如何处理操作1和2.(这点没想到).. 我们用一个delta维护操作1,如果没有旋转就+k,不然就-k. 每次读入i和 ...

  7. BZOJ1493 NOI2007 项链工厂 线段树模拟

    提交地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1493 题目大意:给一个数列,进行一系列操作.包括旋转,翻转,改变等操作,以及查询颜色段数. ...

  8. NOI2007项链工厂——sbTreap代码

    #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> ...

  9. NOI2007 项链工厂

    题目链接:戳我 60pts 有一点容易写错的小细节: 比如说求全局的段数的时候,如果只有一种颜色,那么当左右端点相等时,就不要ans--了. 注意右端点小于左端点的情况. #include<io ...

  10. 【BZOJ-1493】项链工厂 Splay

    1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 1440  Solved: 626[Submit][Status] ...

随机推荐

  1. FFmpeg开发笔记全目录(FFmpeg开发实战详解,含直播系统的搭建过程)

    ​记录下FFmpeg的学习笔记目录,完整的FFmpeg开发实战内容详见<FFmpeg开发实战:从零基础到短视频上线>一书. 下面是补充的FFmpeg开发笔记内容目录,主要是对<FFm ...

  2. 只听过 Python 做爬虫?不瞒你说 Java 也很强

    网络爬虫技术,早在万维网诞生的时候,就已经出现了,今天我们就一起来揭开它神秘的面纱! 一.摘要 说起网络爬虫,相信大家都不陌生,又俗称网络机器人,指的是程序按照一定的规则,从互联网上抓取网页,然后从中 ...

  3. 实验11.ACL实验

    # 实验11.ACL实验 本实验用于测试ACL,类似于防火墙. 拓扑 要求阻塞PC1到PC2和server的全部协议,阻塞client1到server1的icmp协议 具体配置 首先利用ospf协议实 ...

  4. Prometheus监控系统(二)Prometheus部署与使用

    1. Prometheus安装 官网:https://prometheus.io/ 下载地址:https://prometheus.io/download/ Prometheus基于Golang编写, ...

  5. Linux 内核:设备树(3)把device_node转换成platfrom_device

    Linux 内核:设备树(3)把device_node转换成platfrom_device 背景 在上一节中讲到设备树dtb文件中的各个节点转换成device_node的过程(<dtb转换成de ...

  6. Oracle常用统计

    测试, 这是测消息 1.按天 select to_char(t.STARTDATE+15/24, 'YYYY-MM-DD') as 天,sum(1) as 数量from HOLIDAY tgroup ...

  7. Codeforces Global Round 26 A~C2

    惹啊啊啊啊,这场做得我发昏,最近总感觉不在状态,但还是再在冲击1600-1800的题目. A. Strange Splitting ---------------------------------题 ...

  8. 200 行 ,一个PYQT 窗口 + 后台 AIOHTTP 服务 , 例子

    直接上代码 import sys from typing import Dict, List from aiohttp import web import asyncio from functools ...

  9. Babel 7 初探

    Babel有两大功能,转译和polyfill.转译就是把新的JS的语法,转化成旧的JS的语法.polyfill则是针对JS中新增的一些对象(Map, Set)和实例方法,这些对象和方法,在旧的浏览器中 ...

  10. linux常见终端命令和一些小问题的解决

    此文章为linux常见终端命令汇总和一些小问题的解决方法,会不定期更新. [常见指令] 1. 误按 Ctrl+s 锁住终端. ubuntu16命令行误按 Ctrl + s 导致终端锁定,Ctrl + ...