[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;
}