P5350 序列
详见题目描述。
先利用 split 操作得到左右端点的迭代器,然后直接暴力遍历即可。记得不要忘记取模
ODT 基础操作,区间推平,这里不作详细
解释。
跟操作1类似,暴力遍历即可。
先将区间 [ l 2 , r 2 ] [l_2,r_2] [l2,r2] 删掉,然后设 d i s t a n c e = l 2 − l 1 distance=l_2-l_1 distance=l2−l1,暴力遍历区间 [ l 1 , r 1 ] [l_1,r_1] [l1,r1],将里面的每个小区间的范围加上 v a l val val 并加入到 s e t set set 中即可。
我们利用 swap 的原理,先把区间 [ l 1 , r 1 ] [l_1,r_1] [l1,r1] 复制给 n n n 后面的一个区间,
再把区间 [ l 2 , r 2 ] [l_2,r_2] [l2,r2]复制给区间 [ l 1 , r 1 ] [l_1,r_1] [l1,r1],最后把第一步中的区间复制给区间 [ l 2 , r 2 ] [l_2,r_2] [l2,r2]。
利用判断回文串的原理。首先遍历这个区间,假设当前区间的下标分别为 l 1 l_1 l1, r 1 r_1 r1,那它反转后对应得下标为 l + r − r 1 l+r-r_1 l+r−r1, l + r − l 1 l+r-l_1 l+r−l1. 我们拿个数组存一下这些操作,遍历完之后再把它们插入即可。
最后将 1 1 1~ n n n 遍历输出即可。
#include
using namespace std;
int n,m,v[300000+10];
const long long mod=1e9+7;
struct node
{
int l,r;
mutable long long v;
node(int L,int R=-1,int V=0)
{
l=L,r=R,v=V;
}
bool operator<(const node &a) const
{
return l<a.l;
}
};
set<node> a;
#define at set<node>::iterator
struct operate
{
int l,r;
long long v;
}op[300000+10];
at split(int pos)
{
at it=a.lower_bound(pos);
if(it!=a.end()&&it->l==pos)
return it;
it--;
int l=it->l;
int r=it->r;
int v=it->v;
a.erase(it);
a.insert(node(l,pos-1,v));
return a.insert(node(pos,r,v)).first;
}
int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
s=s*10+(ch-'0'),ch=getchar();
return s*w;
}
void work1()
{
int l=read(),r=read();
long long ans=0;
at itr=split(r+1);
at itl=split(l);
for(at it=itl;it!=itr;++it)
ans=(ans+(it->r-it->l+1)*it->v)%mod;
printf("%lld\n",ans);
}
void work2(int l,int r,int v)
{
at itr=split(r+1);
at itl=split(l);
a.erase(itl,itr);
a.insert(node(l,r,v));
return ;
}
void work3()
{
int l=read(),r=read(),v=read();
at itr=split(r+1);
at itl=split(l);
for(at it=itl;it!=itr;++it)
it->v=(it->v+v)%mod;
return ;
}
void work4(int l1,int r1,int l2,int r2)
{
int l=0;
at itr=split(r1+1);
at itl=split(l1);
int val=l2-l1;
for(at it=itl;it!=itr;++it)
op[++l]=(operate){it->l+val,it->r+val,it->v};
itr=split(r2+1);
itl=split(l2);
a.erase(itl,itr);
for(int i=1;i<=l;++i)
a.insert(node(op[i].l,op[i].r,op[i].v));
return ;
}
void work5()
{
int l1=read(),r1=read(),l2=read(),r2=read();
work4(l1,r1,n+1,n+r1-l1+1);
work4(l2,r2,l1,r1);
work4(n+1,n+r1-l1+1,l2,r2);
return ;
}
void work6()
{
int l=read(),r=read(),siz=0;
at itr=split(r+1);
at itl=split(l);
for(at it=itl;it!=itr;++it)
op[++siz]=(operate){l+r-it->r,l+r-it->l,it->v};
a.erase(itl,itr);
for(int i=1;i<=siz;++i)
a.insert(node(op[i].l,op[i].r,op[i].v));
return ;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;++i)
v[i]=read();
for(int i=1;i<=n;++i)
{
int l=i,r=i;
while(r+1<=n&&v[r+1]==v[l])
r++;
a.insert(node(l,r,v[l]));
i=r;
}
a.insert(node(n+1,n+10,1e9+8));
for(int i=1;i<=m;++i)
{
int opt=read();
if(opt==1)
work1();
if(opt==2)
{
int l=read(),r=read(),v=read();
work2(l,r,v);
}
if(opt==3)
work3();
if(opt==4)
{
int l1=read(),r1=read(),l2=read(),r2=read();
work4(l1,r1,l2,r2);
}
if(opt==5)
work5();
if(opt==6)
work6();
}
at itr=split(n+1);
for(at it=a.begin();it!=itr;++it)
{
for(int i=it->l;i<=it->r;++i)
printf("%lld ",it->v%mod);
}
return 0;
}