1. 程式人生 > >【COGS 2633】數列操作e

【COGS 2633】數列操作e

【題目】

傳送門

題目描述:

一個長度為 nn 的序列,一開始序列數的權值都是 00,有 mm 次操作

支援兩種操作:

  • 11 ll rr xx,給區間 [ ll , rr ] 內,第一個數加 xx,第二個數加 22x2^2\cdot x,第三個數加 32x3^2⋅x......rl+1r-l+1 個數加 (rl+1)2x(r−l+1)^2⋅x
  • 22 ll rr 查詢區間 [ ll , rr ] 內的權值和

每次詢問的答案對 2642^{64} 取模

輸入格式:

第一行兩個數 nnmm,表示序列長度和操作次數

接下來 mm 行,每行描述一個操作,有如下兩種情況:

  • 11 ll rr xx,給區間 [ ll , rr ] 內,第一個數加 xx,第二個數加 22x2^2⋅x,第三個數加 32x3^2⋅x…第 rl+1r-l+1 個數加 (rl+1)2x(r−l+1)^2⋅x
  • 22 ll rr 查詢區間 [ ll , rr ] 內的權值和

輸出格式:

為了減少輸出,你只需要輸出所有答案對 2642^{64} 取膜之後的異或和。

樣例資料:

輸入
5 5
1 3 4 1
2 1 5
2 2 2
1 3 3 1
1 2 4 1

輸出
5

提示:

對於 10%10\% 的資料,n,m2000n,m ≤ 2000
對於 30%30\% 的資料,n,m10000n,m ≤ 10000
對於 100%100\% 的資料,n,m100000n,m ≤ 1000001lrn1 ≤ l ≤ r ≤ n0x1090 ≤ x ≤ 10^9


【分析】

這道題可以看做是區間加一個二次函式,比較容易可以想到用線段樹做

對於一個 11 ll rr xx 的詢問,iilirl≤i≤r) 位置加上的值為 (il+1)2x(i-l+1)^2\cdot x,看起來不太好求區間和,怎麼辦呢?

實際上把式子拆開,可以得到 i2x+2i(1l)x+(l1)2xi^2\cdot x+2i(1-l)\cdot x+(l-1)^2\cdot x,那麼用三個陣列分別維護 xx2(1l)x2(1-l)\cdot x(l1)2x(l-1)^2\cdot x,然後預處理出 iii2i^2 的字首和就可以快速合併了,下傳也比較容易

然後看到對 2642^{64} 取模就直接用 unsignedunsigned longlong longlong 就行了


【程式碼】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define ull unsigned long long
using namespace std;
int n,m,L,R;
ull S[N][2],sum[N<<2][3],add[N<<2][3];
void Pushup(int root)
{
	sum[root][0]=sum[root<<1][0]+sum[root<<1|1][0];
	sum[root][1]=sum[root<<1][1]+sum[root<<1|1][1];
	sum[root][2]=sum[root<<1][2]+sum[root<<1|1][2];
}
void Pushnow(int root,int l,int r,ull w1,ull w2,ull w3)
{
	sum[root][0]+=w1*(r-l+1);
	sum[root][1]+=w2*(S[r][0]-S[l-1][0]);
	sum[root][2]+=w3*(S[r][1]-S[l-1][1]);
	add[root][0]+=w1,add[root][1]+=w2,add[root][2]+=w3;
}
void Pushdown(int root,int l,int r,int mid)
{
	Pushnow(root<<1,l,mid,add[root][0],add[root][1],add[root][2]);
	Pushnow(root<<1|1,mid+1,r,add[root][0],add[root][1],add[root][2]);
	add[root][0]=add[root][1]=add[root][2]=0;
}
void Modify(int root,int l,int r,int x,int y,int val)
{
	if(l>=x&&r<=y)
	{
		Pushnow(root,l,r,(ull)val*(L-1)*(L-1),(ull)2*val*(1-L),(ull)val);
		return;
	}
	int mid=(l+r)>>1;
	Pushdown(root,l,r,mid);
	if(x<=mid)  Modify(root<<1,l,mid,x,y,val);
	if(y>mid)  Modify(root<<1|1,mid+1,r,x,y,val);
	Pushup(root);
}
ull Query(int root,int l,int r,int x,int y)
{
	if(l>=x&&r<=y)
	  return sum[root][0]+sum[root][1]+sum[root][2];
	ull ans=0;int mid=(l+r)>>1;
	Pushdown(root,l,r,mid);
	if(x<=mid)  ans+=Query(root<<1,l,mid,x,y);
	if(y>mid)  ans+=Query(root<<1|1,mid+1,r,x,y);
	return ans;
}
int main()
{
	freopen("rneaty.in","r",stdin);
	freopen("rneaty.out","w",stdout);
	int s,i,x;ull ans=0;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)
	{
		S[i][0]=S[i-1][0]+(ull)i;
		S[i][1]=S[i-1][1]+(ull)i*i;
	}
	for(i=1;i<=m;++i)
	{
		scanf("%d%d%d",&s,&L,&R);
		if(s==1)  scanf("%d",&x),Modify(1,1,n,L,R,x);
		if(s==2)  ans^=Query(1,1,n,L,R);
	}
	printf("%llu",ans);
	fclose(stdin);
	fclose(stdout);
	return 0;
}