题解 数列维护 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;
}
posted @ 2022-07-09 21:02  Administrator-09  阅读(3)  评论(0编辑  收藏  举报