题面:https://ac.nowcoder.com/acm/contest/5157/C
题解
线段树裸题
由于一个细节调了我50min
void insert(int i,int l,int r,LL f,LL d)
{
if(a[i].l>r||a[i].r<l)return;
pushdown(i);
if(l<=a[i].l&&a[i].r<=r){cal(i,(f+d*(a[i].l-l))%mod,d);return;}//!!!!!!!!
insert(lc,l,r,f,d);insert(rc,l,r,f,d);
a[i].x=(a[lc].x+a[rc].x)%mod;
}
下传标记的时候分离了等差数列
却忘了在insert的时候分离等差数列
不注重细节!!惨痛教训!!!
其他问题
一开始写线段树的时候维护了24个标记,然后T了
后来想到一些数论的东西,发现只需要mod 3*5*7*11*13*17*19*23就可以了
query的时候再来mod一下
证明挺显然的
这本应该是一个线段树基础题的
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 200005
#define LL long long
const int mod=111546435;
#define lc i<<1
#define rc i<<1|1
int val[N];
struct node{
int l,r;
LL x,f,d,len;
}a[N<<2];
inline void cal(int i,LL f,LL d)
{
(a[i].f+=f)%=mod;(a[i].d+=d)%=mod;
a[i].x=(a[i].x+1ll*f*a[i].len+(1ll*(a[i].len)*(a[i].len-1)/2)%mod*d)%mod;
}
inline void pushdown(int i)
{
if(a[i].f&&a[i].l<a[i].r){
LL f=a[i].f,d=a[i].d;
cal(lc,f,d);
cal(rc,(1ll*f+1ll*a[lc].len*d)%mod,d);
a[i].f=a[i].d=0;
}
}
void build(int i,int l,int r)
{
a[i].l=l;a[i].r=r;a[i].len=r-l+1;
if(l==r){
a[i].x=val[l]%mod;
return;
}
int mid=(l+r)>>1;
build(lc,l,mid);build(rc,mid+1,r);
a[i].x=(a[lc].x+a[rc].x)%mod;
}
void insert(int i,int l,int r,LL f,LL d)
{
if(a[i].l>r||a[i].r<l)return;
pushdown(i);
if(l<=a[i].l&&a[i].r<=r){cal(i,(f+d*(a[i].l-l))%mod,d);return;}//
insert(lc,l,r,f,d);insert(rc,l,r,f,d);
a[i].x=(a[lc].x+a[rc].x)%mod;
}
LL query(int i,int l,int r,int mo)
{
if(a[i].l>r||a[i].r<l)return 0ll;
pushdown(i);
if(l<=a[i].l&&a[i].r<=r)return a[i].x;
return (query(lc,l,r,mo)+query(rc,l,r,mo))%mo;
}
int main()
{
int n,Q,i,op,l,r,mo,f,d;
n=gi();
for(i=1;i<=n;i++)val[i]=gi();
build(1,1,n);
Q=gi();
for(i=1;i<=Q;i++){
op=gi();l=gi();r=gi();
if(op==1){
f=gi();d=gi();
insert(1,l,r,f,d);
}
else{
mo=gi();
printf("%lld\n",query(1,l,r,mo));
}
}
}