[NOI2007] 项链工厂 题解
前言
题目链接:洛谷;Hydro & bzoj。
题意简述
yzh 喜欢写 DS 题!你要维护一个环:
- 顺时针移动 \(k\) 位;
- 翻转 \(2 \sim n\);
- 交换 \(i\) 与 \(j\);
- 区间覆盖;
- 查询整个环有几个颜色段;
- 查询 \(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] 项链工厂 题解的更多相关文章
- BZOJ1493 [NOI2007]项链工厂
未完待续... 终于改对了 热泪盈眶.jpg 错误原因:pushdown的时候没有判断是否有左右儿子,也没当x=0 return,于是出现一些奇怪的错误 #include<bits/stdc++ ...
- bzoj 1493: [NOI2007]项链工厂(线段树)
1493: [NOI2007]项链工厂 Time Limit: 30 Sec Memory Limit: 64 MBSubmit: 1256 Solved: 545[Submit][Status] ...
- 数据结构(Splay平衡树): [NOI2007] 项链工厂
[NOI2007] 项链工厂 ★★★ 输入文件:necklace.in 输出文件:necklace.out 简单对比 时间限制:4 s 内存限制:512 MB [问题描述] T公司是一 ...
- bzoj1493[NOI2007]项链工厂 线段树
1493: [NOI2007]项链工厂 Time Limit: 30 Sec Memory Limit: 64 MBSubmit: 1712 Solved: 723[Submit][Status] ...
- BZOJ_1493_[NOI2007]项链工厂_Splay
BZOJ_1493_[NOI2007]项链工厂_Splay Description T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖.款式多样.价格适中,广受青年人的喜爱. 最近T公司打算 ...
- 1493: [NOI2007]项链工厂
线段树. 真还就是个线段树.. 除去操作1,2的话,线段树很容易就处理了,问题在于如何处理操作1和2.(这点没想到).. 我们用一个delta维护操作1,如果没有旋转就+k,不然就-k. 每次读入i和 ...
- BZOJ1493 NOI2007 项链工厂 线段树模拟
提交地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1493 题目大意:给一个数列,进行一系列操作.包括旋转,翻转,改变等操作,以及查询颜色段数. ...
- NOI2007项链工厂——sbTreap代码
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> ...
- NOI2007 项链工厂
题目链接:戳我 60pts 有一点容易写错的小细节: 比如说求全局的段数的时候,如果只有一种颜色,那么当左右端点相等时,就不要ans--了. 注意右端点小于左端点的情况. #include<io ...
- 【BZOJ-1493】项链工厂 Splay
1493: [NOI2007]项链工厂 Time Limit: 30 Sec Memory Limit: 64 MBSubmit: 1440 Solved: 626[Submit][Status] ...
随机推荐
- PIC18 bootloader之RS485 bootloader
了解更多关于bootloader 的C语言实现,请加我Q扣: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制b ...
- idea部署运行tomcat项目方法
在导航栏点击Add Configuration-或者(打开菜单Run->Edit Configuration) 点击+号,选择Tomcat Server ->选择Local->在Na ...
- 如何使用JavaScript实现在线Excel附件的上传与下载?
前言 在本地使用Excel时,经常会有需要在Excel中添加一些附件文件的需求,例如在Excel中附带一些Word,CAD图等等.同样的,类比到Web端,现在很多人用的在线Excel是否也可以像本地一 ...
- 实验五:FTP远程密码pojie(有敏感词)
[实验目的] 了解远程FTP密码pojie原理,了解如何有效防范类似攻击的方法和措施,掌握pojieftp帐号口令pojie技术的基本原理.常用方法及相关工具. [知识点] FTP口令pojie [实 ...
- [flask]统一API响应格式
前言 在设计API返回内容时,通常需要与前端约定好API返回响应体内容的格式.这样方便前端进行数据反序列化时相应的解析处理,也方便其它服务调用.不同公司有不同的响应内容规范要求,这里以常见的JSON响 ...
- 记一次反向代理过滤sql注入
公司有一php系统,由于该系统是购买的,并且没人懂php,无法通过修改代码过滤sql注入问题 代码如下: public class Program { public static void Main( ...
- ReST,以及RESTful的 简单介绍
什么是 ReST 阮一峰说的比较清楚,具体见他的博客文章. 二.名称 ReST这个词,是[Roy Thomas Fielding](http://en.wikipedia.org/wiki/Roy_F ...
- 统信 UOS 重置Root账号密码 获取 Root 权限
统信服务器默认无法用root 账号登入系统,用普通管理员登入后在切换至root账户下即可,初次使用系统时 切换至root账户前需要做很多配置 1.同信切换root账户首先要激活下系统,可以选择试用期激 ...
- Quarkus初体验:动态加载和原生部署
在前面的文章<尝试官方的第一个SpringNative 0.11程序>中提到过Quarkus这门技术.这里就简单演示一下它的两个主要功能:Live Coding和Native Build. ...
- AT_abc317_f 题解
调了一小时结果发现爆 long long 了. 考虑数位 dp,具体来说,设计状态 \(dp_{i,r_1,r_2,r_3,mx_1,mx_2,mx3_,c_1,c_2,c_3}\) 表示当前考虑到第 ...