有一条长度为n的链( ∀1≤i<n ∀ 1 ≤ i < n ,点i与点i+1之间有一条边的无向图),每个点有一个整数权值,第i个点的权值是ai。现在有 m 个操作,每个操作如下:
操作 1(修改):给定链上两个节点 u、v 和一个整数 d,表示将链上u到 v唯一的简单路径上每个点的权值都加上d。
操作 2(询问):给定两个正整数 l、r,表示求链上所有节点个数大于等于 l且小于等于r的简单路径的节点权值和之和。由于答案很大,只用输出对质数1,000,000,007 取模的结果即可。
一条节点个数为 k 的简单路径的节点权值和为这条路径上所有 k 个节点(包括端点)的权值之和,而本题中要求的是对所有满足要求的简单路径,求这一权值和的和。
由于是无向图,路径也是无向的,即点1到点2的路径与点2到点1的路径是同一条,不要重复计算。
别被 u>v u > v 坑了!!!!!
这是今天比赛的最水的一题,但是我看错题了。我以为不是链,结果gg了。
然后就很容易地发现了答案:
#include
#include
#include
#include
#include
#define N 200010
#define LL long long
#define mo 1000000007
#define P(a) putchar(a)
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct note1{
LL sum,a,b,c,la,lb,lc;
};note1 tr[N*4];
int i,j,k,l,r,n,m,u,op;
LL A,B,C,A1,B1,C1,opl,opr;
LL umi,Ny;
LL a[N],qz[N],c[N];
LL ans,lim;
int read(){
int fh=1,rs=0;char ch;
while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
return fh*rs;
}
void write(LL x){
if(x>9)write(x/10);
P(x%10+'0');
}
LL sum1(LL x){return x*(x+1)>>1;}
LL sum2(LL x){return x*(x+1)*((x<<1)+1)/6;}
void Add(LL &x,LL y){
x=x+y>=mo?x+y-mo:x+y;
}
LL Min(LL x,LL y){return x<y?x:y;}
void add(int ps,LL l,LL r){
LL temp=(A1*((sum2(r)-sum2(l-1)+mo)%mo)%mo+B1*(sum1(r)-sum1(l-1))%mo+C1*(r-l+1)%mo)%mo;
Add(tr[ps].sum,temp);
Add(tr[ps].la,A1);Add(tr[ps].lb,B1);Add(tr[ps].lc,C1);
}
void downld(int ps,int l,int r){
if(!tr[ps].la&&!tr[ps].lb&&!tr[ps].lc)return;
int wz=(l+r)>>1;
A1=tr[ps].la;
B1=tr[ps].lb;
C1=tr[ps].lc;
add(ps<<1,l,wz);
add((ps<<1)|1,wz+1,r);
tr[ps].la=tr[ps].lb=tr[ps].lc=0;
}
void update(int ps){
tr[ps].sum=(tr[ps<<1].sum+tr[(ps<<1)|1].sum)%mo;
}
void change(int ps,int l,int r,int x,int y){
if(x>y)return;
if(l==x&&r==y){
A1=A;B1=B;C1=C;
add(ps,l,r);
return;
}
downld(ps,l,r);
int wz=(l+r)>>1;
if(y<=wz)change(ps<<1,l,wz,x,y);else
if(x>wz)change((ps<<1)|1,wz+1,r,x,y);else{
change(ps<<1,l,wz,x,wz);
change((ps<<1)|1,wz+1,r,wz+1,y);
}
update(ps);
}
void modify(LL x,LL y){
x=Min(x,n-x+1);
y=Min(y,n-y+1);
if(x>y)swap(x,y);
A=0;B=u*(y-x+1)%mo;C=0;
change(1,1,n,1,y);
A=(-u*Ny%mo+mo)%mo;B=((-u*(-2*x+1)%mo+mo)%mo*Ny%mo+mo)%mo;C=((-u*(x*x%mo-x)%mo+mo)%mo*Ny)%mo;
change(1,1,n,x+1,y);
A=0;B=0;C=(((x+y)*(y-x+1)%mo)*u%mo)*Ny%mo;
change(1,1,n,y+1,lim);
}
LL query(int ps,int l,int r,int x,int y){
if(l==x&&r==y)return tr[ps].sum;
downld(ps,l,r);
int wz=(l+r)>>1;
if(y<=wz)return query(ps<<1,l,wz,x,y);else
if(x>wz)return query((ps<<1)|1,wz+1,r,x,y);else
return (query(ps<<1,l,wz,x,wz)+query((ps<<1)|1,wz+1,r,wz+1,y))%mo;
}
LL work(int x,int y){
x=Min(x,n-x+1);
y=Min(y,n-y+1);
if(x>y)swap(x,y);
return query(1,1,n,x,y);
}
int main(){
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
Ny=500000004;
n=read();m=read();
fo(i,1,n)a[i]=read(),qz[i]=(qz[i-1]+a[i])%mo,c[i]=min(i,n-i+1);
umi=0;
lim=(n+1)>>1;
fo(i,1,lim){
umi=(umi+qz[n-i+1]-qz[i-1]+mo)%mo;
A=0;B=0;C=umi;
change(1,1,n,i,i);
}
while(m--){
op=read();l=read();r=read();
if(l>r)swap(l,r);
if(op==1){
u=read();
if(l<=lim&&r>lim){
modify(l,lim);
modify(lim+1,r);
}else modify(l,r);
}else{
ans=0;
if(l<=lim&&r>lim)ans=(work(l,lim)+work(lim+1,r))%mo;
else ans=work(l,r);
write(ans),P('\n');
}
}
return 0;
}