题解 数列维护 100 合 1
赛时 NT 了到十一点才明白操作 1 放到差分序列上就是直接做
将这段区间单拎出来,其差分序列的和为零
那么最小操作次数就是 \(\frac{\sum |d_i|}{2}\)
然后版本问题可以用操作树解决
- 对于卡空间的可持久化题:要是支持回退的话可以康康能不能用操作树避免可持久化
发现翻转一个区间后差分数组相当于同样翻转再向右平移 1,再单点改掉两个端点处的值
然后就是码支持区间加区间翻转的 FHQ 了
复杂度 \(O(n\log n)\),常数很大
点击查看代码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
// #pragma GCC target("avx", "sse")
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define pb push_back
#define ll long long
// #define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
ll a[N];
// namespace force{
// ll a[1010][1010], tem[N];
// void solve() {
// for (int i=0; i<=n; ++i) a[0][i]=::a[i];
// for (int i=1,op,l,r,x; i<=m; ++i) {
// op=read();
// if (op==1) {
// l=read(); r=read(); ll ans=0;
// for (int j=1; j<=n; ++j) a[i][j]=a[i-1][j];
// tem[l]=a[i][l]; tem[r+1]=-a[i][r];
// for (int j=l+1; j<=r; ++j) tem[j]=a[i][j]-a[i][j-1];
// for (int j=l; j<=r+1; ++j) ans+=abs(tem[j]);
// printf("%lld\n", ans/2);
// }
// else if (op==10) {
// l=read(); r=read(); x=read();
// for (int j=1; j<=n; ++j) a[i][j]=a[i-1][j];
// for (int j=l; j<=r; ++j) a[i][j]+=x;
// }
// else if (op==11) {
// l=read(); r=read();
// for (int j=1; j<=n; ++j) a[i][j]=a[i-1][j];
// for (int x=l,y=r; x<y; swap(a[i][x++], a[i][y--]));
// }
// else {
// x=read();
// for (int j=1; j<=n; ++j) a[i][j]=a[i-x-1][j];
// }
// }
// }
// }
// namespace task1{
// ll ans[N];
// vector<int> to[N];
// int op[N], l[N], r[N], x[N];
// ll a[N], d[N];
// void upd(int l, int r, int x) {
// for (int i=l; i<=r; ++i) a[i]+=x;
// d[l]+=x; d[r+1]-=x;
// }
// ll query(int l, int r) {
// ll ans=abs(a[l])+abs(-a[r]);
// for (int i=l+1; i<=r; ++i) ans+=abs(d[i]);
// return ans/2;
// }
// void reverse(int l, int r) {
// ll t1=a[r]-a[l-1], t2=a[r+1]-a[l];
// for (int i=l,j=r; i<j; swap(a[i++], a[j--]));
// for (int i=l,j=r; i<j; swap(d[i++], d[j--]));
// for (int i=r; i>l; --i) d[i]=-d[i-1];
// d[l]=t1, d[r+1]=t2;
// }
// void dfs(int u) {
// if (op[u]==1) ans[u]=query(l[u], r[u]);
// else if (op[u]==10) upd(l[u], r[u], x[u]);
// else if (op[u]==11) reverse(l[u], r[u]);
// for (auto& v:to[u]) dfs(v);
// if (op[u]==10) upd(l[u], r[u], -x[u]);
// else if (op[u]==11) reverse(l[u], r[u]);
// }
// void solve() {
// for (int i=1; i<=n; ++i) a[i]=::a[i];
// for (int i=1; i<=m; ++i) {
// op[i]=read();
// if (op[i]==1) l[i]=read(), r[i]=read(), to[i-1].pb(i);
// else if (op[i]==10) l[i]=read(), r[i]=read(), x[i]=read(), to[i-1].pb(i);
// else if (op[i]==11) l[i]=read(), r[i]=read(), to[i-1].pb(i);
// else to[i-read()-1].pb(i);
// }
// for (int i=1; i<=n+1; ++i) d[i]=a[i]-a[i-1];
// dfs(0);
// for (int i=1; i<=m; ++i) if (op[i]==1) printf("%lld\n", ans[i]);
// }
// }
namespace task{
ll ans[N];
vector<int> to[N];
random_device seed;
mt19937 rand(seed());
int op[N], l[N], r[N], x[N], cnt[N], now, all;
struct treap1{
bool rev[N];
int val[N], tag[N];
#define son(a, b) son[a][b]
int son[N][2], siz[N], rnd[N], rot, tot;
#define pushup(a) siz[a]=siz[son(a, 0)]+siz[son(a, 1)]+1
inline int setup(int dat) {val[++tot]=dat; rnd[tot]=rand(); siz[tot]=1; return tot;}
inline void spread(int a) {
if (tag[a]) {
if (son(a, 0)) val[son(a, 0)]+=tag[a], tag[son(a, 0)]+=tag[a];
if (son(a, 1)) val[son(a, 1)]+=tag[a], tag[son(a, 1)]+=tag[a];
tag[a]=0;
}
if (rev[a]) {
if (son(a, 0)) swap(son(son(a, 0), 0), son(son(a, 0), 1)), rev[son(a, 0)]^=1;
if (son(a, 1)) swap(son(son(a, 1), 0), son(son(a, 1), 1)), rev[son(a, 1)]^=1;
rev[a]=0;
}
}
void split(int u, int k, int& x, int& y) {
if (!u) {x=y=0; return ;}
spread(u);
if (siz[son(u, 0)]<k) x=u, split(son(u, 1), k-siz[son(u, 0)]-1, son(u, 1), y);
else y=u, split(son(u, 0), k, x, son(u, 0));
pushup(u);
}
int merge(int x, int y) {
if (!(x&&y)) return x|y;
if (rnd[x]<rnd[y]) {spread(x); son(x, 1)=merge(son(x, 1), y); pushup(x); return x;}
else {spread(y); son(y, 0)=merge(x, son(y, 0)); pushup(y); return y;}
}
void build() {for (int i=0; i<=n+1; ++i) rot=merge(rot, setup(a[i]));}
void upd(int l, int r, int k) {
int x, y, z;
split(rot, l-1+1, x, y);
split(y, r-l+1, y, z);
val[y]+=k; tag[y]+=k;
rot=merge(x, merge(y, z));
}
int qval(int k) {
int x, y, z;
split(rot, k-1+1, x, y);
split(y, 1, y, z);
int ans=val[y];
rot=merge(x, merge(y, z));
return ans;
}
void reverse(int l, int r) {
int x, y, z;
split(rot, l-1+1, x, y);
split(y, r-l+1, y, z);
swap(son(y, 0), son(y, 1)); rev[y]^=1;
rot=merge(x, merge(y, z));
}
#undef pushup
}a;
struct treap2{
bool rev[N];
ll val[N], sum[N];
#define son(a, b) son[a][b]
int son[N][2], siz[N], rnd[N], rot, tot;
#define pushup(a) siz[a]=siz[son(a, 0)]+siz[son(a, 1)]+1, sum[a]=sum[son(a, 0)]+sum[son(a, 1)]+val[a]
inline int setup(int dat) {val[++tot]=dat; sum[tot]=dat; rnd[tot]=rand(); siz[tot]=1; return tot;}
inline void spread(int a) {
if (!rev[a]) return ;
if (son(a, 0)) swap(son(son(a, 0), 0), son(son(a, 0), 1)), rev[son(a, 0)]^=1;
if (son(a, 1)) swap(son(son(a, 1), 0), son(son(a, 1), 1)), rev[son(a, 1)]^=1;
rev[a]=0;
}
void split(int u, int k, int& x, int& y) {
if (!u) {x=y=0; return ;}
spread(u);
if (siz[son(u, 0)]<k) x=u, split(son(u, 1), k-siz[son(u, 0)]-1, son(u, 1), y);
else y=u, split(son(u, 0), k, x, son(u, 0));
pushup(u);
}
int merge(int x, int y) {
if (!(x&&y)) return x|y;
if (rnd[x]<rnd[y]) {spread(x); son(x, 1)=merge(son(x, 1), y); pushup(x); return x;}
else {spread(y); son(y, 0)=merge(x, son(y, 0)); pushup(y); return y;}
}
void build() {for (int i=1; i<=n+1; ++i) rot=merge(rot, setup(abs(::a[i]-::a[i-1])));}
void upd(int pos, int k) {
int x, y, z;
split(rot, pos-1, x, y);
split(y, 1, y, z);
val[y]=sum[y]=k;
rot=merge(x, merge(y, z));
}
ll query(int l, int r) {
int x, y, z;
split(rot, l-1, x, y);
split(y, r-l+1, y, z);
ll ans=sum[y];
rot=merge(x, merge(y, z));
return ans;
}
void reverse(int l, int r) {
int x, y, z, t;
split(rot, l-1, x, y);
split(y, r-l+1, y, z);
swap(son(y, 0), son(y, 1)); rev[y]^=1;
split(y, r-l, y, t);
rot=merge(x, merge(merge(t, y), z));
}
}d;
void upd(int l, int r, int x) {
// for (int i=l; i<=r; ++i) a[i]+=x;
a.upd(l, r, x);
d.upd(l, abs(a.qval(l)-a.qval(l-1))); d.upd(r+1, abs(a.qval(r+1)-a.qval(r)));
}
ll query(int l, int r) {
ll ans=abs(a.qval(l))+abs(-a.qval(r));
// for (int i=l+1; i<=r; ++i) ans+=d[i];
if (l<r) ans+=d.query(l+1, r);
return ans/2;
}
void reverse(int l, int r) {
ll t1=abs(a.qval(r)-a.qval(l-1)), t2=abs(a.qval(r+1)-a.qval(l));
// for (int i=l,j=r; i<j; swap(a[i++], a[j--]));
a.reverse(l, r);
// for (int i=l,j=r; i<j; swap(d[i++], d[j--]));
// for (int i=r; i>l; --i) d[i]=d[i-1];
d.reverse(l, r);
d.upd(l, t1), d.upd(r+1, t2);
}
void dfs1(int u) {
cnt[u]=(op[u]==1);
for (auto& v:to[u]) dfs1(v), cnt[u]+=cnt[v];
}
void dfs2(int u) {
if (op[u]==1) ans[u]=query(l[u], r[u]), ++now;
else if (op[u]==10) upd(l[u], r[u], x[u]);
else if (op[u]==11) reverse(l[u], r[u]);
for (auto& v:to[u]) if (cnt[v]) dfs2(v);
if (now==all) return ;
if (op[u]==10) upd(l[u], r[u], -x[u]);
else if (op[u]==11) reverse(l[u], r[u]);
}
void solve() {
a.build(); d.build();
for (int i=1; i<=m; ++i) {
op[i]=read();
if (op[i]==1) l[i]=read(), r[i]=read(), to[i-1].pb(i);
else if (op[i]==10) l[i]=read(), r[i]=read(), x[i]=read(), to[i-1].pb(i);
else if (op[i]==11) l[i]=read(), r[i]=read(), to[i-1].pb(i);
else to[i-read()-1].pb(i);
}
// for (int i=1; i<=n+1; ++i) d[i]=abs(::a[i]-::a[i-1]);
dfs1(0); all=cnt[0]; dfs2(0);
for (int i=1; i<=m; ++i) if (op[i]==1) printf("%lld\n", ans[i]);
}
}
signed main()
{
freopen("sequence.in", "r", stdin);
freopen("sequence.out", "w", stdout);
n=read(); m=read();
for (int i=1; i<=n; ++i) a[i]=read();
// force::solve();
task::solve();
return 0;
}