[Ynoi2014] 人人本着正义之名
考虑 3/4/5/6 操作,发现本质上是对某段颜色相同的段向左/右拓展。
考虑 1/2 为区间推平操作,其它操作只会减少颜色段,因此总颜色段为 \(O(n+m)\) 的,直接平衡树维护即可。
然而巨巨巨巨难写》
Code:
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <cctype>
#include <vector>
#include <queue>
#include <bitset>
#include <iostream>
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define st first
#define nd second
using namespace std;
typedef long long ll;
typedef pair <int, int> Pii;
const int INF=0x3f3f3f3f;
const int cp=998244353;
inline int mod(int x){if(x>=cp) x-=cp;if(x<0) x+=cp;return x;}
inline void plust(int &x, int y){x=mod(x+y);return ;}
inline void minut(int &x, int y){x=mod(x-y);return ;}
inline int read(){
char ch=getchar();int x=0, f=1;
while(!isdigit(ch)){if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
inline void write(int x){
if(x<0) putchar('-'), x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline int ksm(int a, int b=cp-2){
int ret=1;
for(; b; b>>=1, a=1ll*a*a%cp)
if(b&1) ret=1ll*ret*a%cp;
return ret;
}
const int N=3e6+6;
const int M=1e7;
typedef unsigned int ui;
ui seed=20061207;
inline ui rnd(){seed^=seed<<7;seed^=seed>>11;seed^=seed<<13;return seed;}
namespace FHQ{
inline int mn(int a, int b){return (a<b)?a:b;}
struct node{
ui key;int col, sum, siz[2], l, r, tagl, tagr, mnl[2];node *ls, *rs;
//自己的颜色 子树和 子树0/1区间个数 自己的区间 子树 1 端点偏移量 子树0/1最短段长
void up(){siz[col]=1, siz[!col]=0;sum=col*(r-l+1);tagl=tagr=0, mnl[col]=r-l+1, mnl[!col]=INF;}
node(){}node(ui ky, int c, int lp, int rp){key=ky, col=c, l=lp, r=rp, sum=0, ls=NULL, rs=NULL;up();}
void tag(int tl, int tr){
tagl+=tl, tagr+=tr;mnl[0]-=tl+tr, mnl[1]+=tl+tr;sum+=(tl+tr)*siz[1];
if(col) l-=tl, r+=tr;else l+=tr, r-=tl;
}
void print(){printf("%d %d %d %d %d\n", col, sum, l, r, key);}
void pushdown(){
if(tagl||tagr){
if(ls!=NULL) ls->tag(tagl, tagr);
if(rs!=NULL) rs->tag(tagl, tagr);
}tagl=tagr=0;
}
node operator + (const node &R) const{
node res=*this;res.sum+=R.sum;res.siz[0]+=R.siz[0];res.siz[1]+=R.siz[1];
res.mnl[0]=min(res.mnl[0], R.mnl[0]);res.mnl[1]=mn(res.mnl[1], R.mnl[1]);
return res;
}
void pushup(){up();if(ls!=NULL) *this=*this+*(this->ls);if(rs!=NULL) *this=*this+*(this->rs);}
}fhq[M];int ndc;node *root;
inline node* clr(int c, int l, int r){return &(fhq[++ndc]=node(rnd(), c, l, r));}
void splitL(node *k, int v, node *&x, node *&y){
if(k==NULL) return (void)(x=y=NULL);k->pushdown();
if(k->l<=v) x=k, splitL(k->rs, v, x->rs, y);
else y=k, splitL(k->ls, v, x, y->ls);k->pushup();
}
void splitR(node *k, int v, node *&x, node *&y){
if(k==NULL) return (void)(x=y=NULL);k->pushdown();
if(k->r<=v) x=k, splitR(k->rs, v, x->rs, y);
else y=k, splitR(k->ls, v, x, y->ls);k->pushup();
}
node* merge(node *x, node *y){
if(x==NULL) return y;if(y==NULL) return x;
x->pushdown(), y->pushdown();
if(x->key<y->key) return x->rs=merge(x->rs, y), x->pushup(), x;
else return y->ls=merge(x, y->ls), y->pushup(), y;
}
vector<node*> tmp;
void dfs(node *k){
if(k==NULL) return ;if(k->mnl[0]&&k->mnl[1]) return ;k->pushdown();
if(k->l>k->r) tmp.pb(k);dfs(k->ls);dfs(k->rs);
}
inline void maintain(){
vector<node*> ().swap(tmp);dfs(root);
for(int i=0; i<tmp.size(); ++i){
// printf(">>%d\n", i);
node *x=tmp[i], *L=NULL, *M=NULL, *R=NULL, *y=NULL;
splitL(root, x->l-1, root, R);splitL(R, x->l, y, R);splitR(root, x->l-2, root, L);
if(x==y) M=(x->ls==NULL)?x->rs:x->ls;else M=y, M->ls=M->rs=NULL;
if(L!=NULL&&M!=NULL) L->r=M->r, L->up(), M=NULL;
root=merge(merge(merge(root, L), M), R);
}
}
inline void insert(int c, int l, int r){node *p=clr(c, l, r);root=merge(root, p);}
void print(node *k=root){
if(k==NULL) return ;k->pushdown();
printf("[%d %d] col %d %d\n", k->l, k->r, k->col, k->sum);
cout<<k<<" ls="<<k->ls<<" rs="<<k->rs<<endl;
print(k->ls);print(k->rs);
}
inline void mdy(int l, int r, int c){
node *L=NULL, *M=NULL, *R=NULL, *x=NULL;//print();
splitR(root, l-1, root, x);splitL(x, r, x, R);
splitL(x, l-1, L, x);splitR(x, r, x, M);
if(L!=NULL){if(L->r>r) M=clr(L->col, r, L->r);L->r=l-1;L->up();}
else splitR(root, l-2, root, L);
if(M!=NULL) M->l=r+1, M->up();
else splitL(R, r+1, M, R);
x=clr(c, l, r);if(L!=NULL&&L->col==c) x->l=L->l, x->up(), L=NULL;
if(M!=NULL&&c==M->col) x->r=M->r, x->up(), M=NULL;
root=merge(merge(merge(merge(root, L), x), M), R);
}
inline void nxt_mdy(int l, int r, int tl, int tr){
node *x=NULL, *y=NULL, *R=NULL;
splitR(root, l-1, root, y);splitL(y, r, y, R);splitL(y, l, x, y);
if(x!=NULL&&x->col==tl) root=merge(root, x);
else y=merge(x, y);x=NULL;splitR(y, r-1, y, x);
if(x!=NULL&&x->col==abs(tr)){
if(x->r>r) R=merge(x, R);
else{
y=merge(y, x);node *M=NULL;
splitL(R, r+1, M, R);y=merge(y, M);
}
}
else y=merge(y, x);if(y!=NULL) y->tag(tl, tr);
root=merge(merge(root, y), R);maintain();
}
void lst_mdy(int l, int r, int tl, int tr) {
node *x=NULL, *y=NULL, *R=NULL;
splitR(root, l-1, root, y);splitL(y, r, y, R);splitL(y, l, x, y);
if(x!=NULL&&x->col==abs(tl)) {
if(x->l<l) root=merge(root, x);
else{
y=merge(x, y);node *M=NULL;
splitR(root, l-2, root, M);y=merge(M, y);
}
}
else y=merge(x, y);x=NULL;
splitR(y, r-1, y, x);
if(x!=NULL&&x->col==tr) R=merge(x, R);
else y=merge(y, x);
if(y!=NULL) y->tag(tl, tr);
root=merge(merge(root, y), R);maintain();
}
inline int qry(int l, int r){
node *p=NULL, *q=NULL, *R=NULL;int res=0;
splitR(root, l-1, root, p);splitL(p, r, p, R);
if(p!=NULL) res+=p->sum;splitL(p, l-1, q, p);
if(q!=NULL) res-=q->col*(l-q->l);p=merge(q, p);q=NULL;
splitR(p, r, p, q);if(q!=NULL) res-=q->col*(q->r-r);
root=merge(merge(root, merge(p, q)), R);return res;
return res;
}
}
int n, m;bool a[N];
signed main(){
n=read(), m=read();
for(int i=1, j=1; i<=n; ++i){
char ch=getchar();while(!isdigit(ch)) ch=getchar();
// printf("-----%c\n", ch);
a[i]=ch-'0';if(i>1&&a[i]!=a[i-1]) FHQ :: insert(a[i-1], j, i-1), j=i;
if(i==n) FHQ :: insert(a[n], j, i);
}
for(int i=1, ans=0; i<=m; ++i){
int op=read(), l=read()^ans, r=read()^ans;
if(l>r) swap(l, r);
if(op<=2) FHQ :: mdy(l, r, op-1);
else if(op==7) printf("%d\n", ans=FHQ :: qry(l, r));
else if(op&1) FHQ :: nxt_mdy(l, r-1, op==3?1:0, op==3?0:-1);
else FHQ :: lst_mdy(l+1, r, op==4?0:-1, op==4?1:0);
// FHQ :: print();puts("");
}
return 0;
}
[Ynoi2014] 人人本着正义之名的更多相关文章
- [Ynoi2014]不归之人与望眼欲穿的人们
题目大意: 给定一个序列,每次单点修改一个数,或给定$x$,询问最短的or起来大于等于$x$的区间的长度(不存在输出-1). 解题思路: 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后,不归 ...
- [Ynoi2015]即便看不到未来
题目大意: 给定一个序列,每次询问,给出一个区间$[l,r]$. 设将区间内的元素去重后重排的数组为$p$,求$p$中长度为$1\sim 10$的极长值域连续段个数. 长度为$L$的极长值域连续段的定 ...
- [Ynoi2015]纵使日薄西山
题目大意: 给定一个序列,每次单点修改,然后进行询问. 定义一次操作为,选择一个位置$x$,将这个位置的数和左边.右边两个位置的数(不存在则忽略)各减去1,然后和0取max. 对序列中最大的位置进行一 ...
- [Ynoi2015]盼君勿忘
题目大意: 给定一个序列,每次查询一个区间\([l,r]\)中所有子序列分别去重后的和\(\bmod p\)(每次询问模数不同). 解题思路: 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后 ...
- [Ynoi2015]我回来了
题目大意: 给定一张无向无权图,每次给定若干个二元组\((x_i,y_i)\),定义点\(u\)满足条件,当且仅当存在\(i\),并满足\(dist(u,x_i)\leqslant y_i\)(\(d ...
- [Ynoi2015]此时此刻的光辉
题目大意: 给定一个序列,每次询问一段区间的数的乘积的约数个数. 解题思路: 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去.逐 ...
- 题解 P5072 【[Ynoi2015] 盼君勿忘】
在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去.逐渐消逝的未来.我回来了,纵使日薄西山,即便看不到未来,此时此刻的光辉,盼君勿忘 ...
- Do you have an English name? 你有英文名吗?
文中提到的所有人名都是虚构的,如有雷同,纯属巧合. 当然,你的洋名儿也可能是德文.法文.意大利文,等々々々. 全球化时代,和老外的交流也多了."高端"的程序员想要进欧美系外企,想要 ...
- 自学JQuery Mobile的几个例子
JQuery Mobile是一个用于构建移动Web应用程序的框架,适用于主流的移动设备(智能手机.平板电脑),该框架利用了HTML5和CSS3技术减少了额外的脚本文件的编写.具体JQuery Mobi ...
- The fifth day
All men cannot be first . 今日单词: first(形容词):第一的:基本的:最早的:(副词):第一:首先 翻译:不可能人人都是第一名. <Only Love>-- ...
随机推荐
- 【SpringMVC】概述
SpringMVC 概述 Spring 为展现层提供的基于 MVC 设计理念的优秀的 Web 框架,是目前最主流的 MVC 框架之一 Spring3.0 后全面超越 Struts2,成为最优秀的 MV ...
- Windows Server 2012 配置 FTP
环境 Windows Server 2012 安装步骤 打开服务器管理器 管理 - 添加角色和功能 开始之前 选择安装类型 服务器选择 选择对应的服务器... 服务器角色 功能 确认 安装进度 配置步 ...
- DotNetGuide 突破了 8K + Star,努力打造C#/.NET/.NET Core全面的学习、工作、面试指南知识库!
前言 转眼之间维护DotNetGuide(全面的C#/.NET/.NET Core学习.工作.面试指南知识库)已经持续超过了4年多的时间,Commit提交数也超过1400+,在前几天在 GitHub ...
- 邮件自动回复助手(Rasa/SMTP)实现教程
在现代办公场景中,处理大量邮件是一项既耗时又容易出错的任务.为了提升工作效率,我们可以利用自然语言处理(NLP)和邮件传输协议(SMTP)技术,构建一个智能的邮件自动回复助手.本文将详细介绍如何使用P ...
- Windows系统优化 3-清理预安装软件
事件起因: 经过我们上次 Windows系统优化 2-系统设置优化 之后,现在电脑已经基本上可以使用,不过对于有强迫症的我来说还差了一步,那就是系统预安装的软件: 对于我们刚入手的电脑你是否有 这些 ...
- 可视化图解算法:按之字形顺序打印二叉树( Z字形、锯齿形遍历)
1. 题目 描述 给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替) 数据范围:0≤n≤1500,树上每个节点的val满足 |val| <= 1500 ...
- SQL 日常练习 (二十)
也只是尽快搬完这快一个月 sql 的砖, 准备要来整新学习模块了, 因此, 正好趁着五一, 加波速. 也会一直坚守和追求, 学无止境, 气有浩然. 每次都会说, 这是一种精神的传承,而我想的是, 不仅 ...
- Ubuntu20.04 搭建Kubernetes 1.28版本集群
环境依赖 以下操作,无特殊说明,所有节点都需要执行 安装 ssh 服务 安装 openssh-server sudo apt-get install openssh-server 修改配置文件 vim ...
- Bolt DIY架构揭秘:从模型初始化到响应生成的技术之旅
Bolt DIY 是一个强大的开源AI辅助开发工具,允许用户在浏览器中进行全栈Web开发.它的核心特点是支持多种大型语言模型(LLM),包括OpenAI.Anthropic.Ollama.Google ...
- 网络编程:UDP connect连接
UDP connect的作用 UDP connect函数的调用,并不会引起像TCP连接那样,和服务器目标端网络交互,并不会触发所谓的"握手"报文发送和应答. UDP套接字进行con ...