题解:序列

题目传送门

ODT 珂朵莉树

如果你不会,你可以看看:ODT 珂朵莉树

数据随机,且有区间赋值,因此考虑 ODT。

操作 \(1\sim3\) 是简单的,考虑操作 \(4\sim6\)

操作 \(4\):区间复制

区间不交,分别 split 操作后,暴力记录 \([l_1,r_1]\) 的信息,删除 \([l_2,r_2]\) 的信息再插入记录信息即可。

同时注意区间端点需要偏移,偏移量为 \(l_2-l_1=r_2-r_1\)

操作 \(5\):区间交换

区间交换,可以分别记录两个区间的信息,删除原信息后插入即可。

同时注意端点需要偏移,偏移量为 \(\pm(l_2-l_1)=\pm(r_2-r_1)\)

操作 \(6\):区间翻转

在区间 \([l,r]\) 内有多个区间 \([l_1,r_1],[l_2,r_2],\cdots,[l_k,r_k]\),需要翻转。

发现翻转得到的 \([l_i',r_i']\) 相对于原区间 \([l_i,r_i]\),有:

\[\begin{aligned} l_i'&=l+r-r_i\\ r_i'&=l+r-l_i \end{aligned} \]

因此可以记录信息,删除后插入。

AC 代码

注意迭代器失效问题。

放一组数据供调试
20 20
304918551 41464763 626731291 93384272 932133547 58912715 131988999 702069776 263423490 347646978 59122396 563111221 416760930 459270045 184611400 242744859 821538911 367584997 718440022 971034462 
4 11 13 5 7
6 5 10
2 14 20 185648890
2 8 13 39249510
1 2 15
1 3 5
5 10 11 15 16
4 5 7 17 19
6 5 15
3 9 19 742600878
6 4 4
3 1 17 13105838
5 3 5 13 15
3 3 9 720875841
3 7 11 551893354
1 10 20
5 1 6 8 13
5 4 8 11 15
6 4 17
2 2 13 341469949
681515396
67762534
968391129
325124536 341469949 341469949 341469949 341469949 341469949 341469949 341469949 341469949 341469949 341469949 341469949 341469949 106490110 919630569 824229528 740006040 6024361 444670647 185648890
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<set>
using namespace std;
typedef long long ll;
constexpr const int N=1e5,P=1e9+7;
int n;
struct ODT{
	struct node{
		int l,r;
		mutable int value;
	};
	friend bool operator <(node a,node b){
		return a.l<b.l;
	}
	set<node>t;
	void build(int l,int r){
		t.clear();
		t.insert({l,r+1});
	}
	auto split(int x){
		auto p=t.lower_bound({x});
		if(p!=t.end()&&p->l==x){
			return p;
		}
		p=prev(p);
		int l=p->l,r=p->r,value=p->value;
		t.erase(p);
		t.insert({l,x-1,value});
		return t.insert({x,r,value}).first;
	}
	void assign(int l,int r,int value){
		auto pr=split(r+1);
		auto pl=split(l);
		t.erase(pl,pr);
		t.insert({l,r,value});
	}
	void add(int l,int r,int x){
		auto pr=split(r+1);
		auto pl=split(l);
		for(auto i=pl;i!=pr;i=next(i)){
			i->value=(i->value + x)%P;
		}
	}
	int sum(int l,int r){
		auto pr=split(r+1);
		auto pl=split(l);
		int ans=0;
		for(auto i=pl;i!=pr;i=next(i)){
			ans=(ans + i->value * (i->r - i->l + 1ll) )%P;
		}
		return ans;
	}
	void copy(int l1,int r1,int l2,int r2){
		auto pr1=split(r1+1);
		auto pl1=split(l1);
		vector<node>s;
		for(auto i=pl1;i!=pr1;i=next(i)){
			s.push_back(*i);
		}
		auto pr2=split(r2+1);
		auto pl2=split(l2);
		t.erase(pl2,pr2);
		for(auto i:s){
			t.insert({i.l+l2-l1,i.r+r2-r1,i.value});
		} 
	}
	void swap(int l1,int r1,int l2,int r2){
		if(l1>l2){
			std::swap(l1,l2);
			std::swap(r1,r2);
		}
		auto pr2=split(r2+1);
		auto pl2=split(l2);
		auto pr1=split(r1+1);
		auto pl1=split(l1);
		vector<node>s1,s2;
		for(auto i=pl1;i!=pr1;i=next(i)){
			s1.push_back(*i);
		}
		for(auto i=pl2;i!=pr2;i=next(i)){
			s2.push_back(*i);
		}
		t.erase(pl1,pr1);
		pr2=split(r2+1);
		pl2=split(l2);
		t.erase(pl2,pr2);
		for(auto i:s1){
			t.insert({i.l+l2-l1,i.r+r2-r1,i.value});
		}
		for(auto i:s2){
			t.insert({i.l+l1-l2,i.r+r1-r2,i.value});
		}
	}
	void reverse(int l,int r){
		if(l>r){
			std::swap(l,r);
		} 
		auto pr=split(r+1);
		auto pl=split(l);
		vector<node>s;
		for(auto i=pl;i!=pr;i=next(i)){
			s.push_back(*i);
		}
		t.erase(pl,pr);
		for(auto i:s){
			t.insert({l+r-i.r,l+r-i.l,i.value});
		}
	}
}t;
main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	int m;
	cin>>n>>m;
	t.build(1,n);
	for(int i=1;i<=n;i++){
		int a;
		cin>>a;
		t.assign(i,i,a);
	} 
	while(m--){
		int op,l1,r1,l2,r2,x;
		cin>>op>>l1>>r1;
		switch(op){
			case 1:
				cout<<t.sum(l1,r1)<<'\n';
				break;
			case 2:
				cin>>x;
				t.assign(l1,r1,x);
				break;
			case 3:
				cin>>x;
				t.add(l1,r1,x);
				break;
			case 4:
				cin>>l2>>r2;
				t.copy(l1,r1,l2,r2);
				break;
			case 5:
				cin>>l2>>r2;
				t.swap(l1,r1,l2,r2);
				break;
			case 6:
				t.reverse(l1,r1);
				break;
		}
	}
	for(int i=1;i<=n;i++){
		cout<<t.sum(i,i)<<' ';
	}
	cout<<'\n';
	
	cout.flush();
	 
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
posted @ 2025-08-17 14:00  TH911  阅读(6)  评论(0)    收藏  举报