nssl 1467.U

D e s c r i p t i o n Description Description

给定一个 n × n n\times n n×n的矩阵,有 q q q次操作,每次会使一个左上角为 ( r , c ) (r,c) (r,c),边长为 l l l的等腰直角三角形内所有的数加 s s s

q q q次操作后,矩阵内所有数的亦或和

数据范围: n ≤ 1 0 3 , q ≤ 3 × 1 0 5 n\leq 10^3,q\leq 3\times 10^5 n103,q3×105


S o l u t i o n Solution Solution

我们把三角形区域的区间加看做若干个纵列的区间加,显然我们只需要标记最上面那个点,然后差分,可以做到 O ( n 2 + q n ) O(n^2+qn) O(n2+qn)

注意到上面那个点如果斜着看也是连续的,所以可以斜着做差分,然后把多余的部分减去即可,这样就是 O ( n 2 + q ) O(n^2+q) O(n2+q)


C o d e Code Code

#include
#include
#include
#define LL long long
using namespace std;int n,q,r,c,l,s;
LL ans,Sz[1011][1011],Sh[1011][1011],a[1011][1011];
inline LL read()
{
	LL d=1,f=0;char c;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline void pushdown(int i,int j)
{
	Sz[i][j]+=Sz[i-1][j-1];
	if(i<n&&j<n) pushdown(i+1,j+1);
	return;
}
signed main()
{
//	freopen("1.txt","r",stdin);
	n=read();q=read();
	for(register int i=1;i<=q;i++)
	{
		r=read();c=read();l=read();s=read();
		Sz[r][c]+=s;Sz[min(r+l,n+1)][min(c+l,n+1)]-=s;
		Sh[min(r+l,n+1)][c]-=s;Sh[min(r+l,n+1)][min(c+l,n+1)]+=s;
	}
	pushdown(1,1);
	for(register int i=2;i<=n;i++)
	{
		pushdown(i,1);
		pushdown(1,i);
	}
	for(register int i=1;i<=n;i++)
	 for(register int j=1;j<=n;j++)
	  Sh[i][j]+=Sh[i][j-1];
	for(register int j=1;j<=n;j++)
	 for(register int i=1;i<=n;i++)
	  Sz[i][j]+=Sz[i-1][j],Sh[i][j]+=Sh[i-1][j];
	for(register int i=1;i<=n;i++)
	 for(register int j=1;j<=n;j++)
	  ans^=Sh[i][j]+Sz[i][j]/*,a[i][j]=Sh[i][j]+Sz[i][j]*/;
	/*for(register int i=1;i<=n;putchar(10),i++)
	 for(register int j=1;j<=n;j++)
	  printf("%3d",a[i][j]);
	putchar(10);*/
	printf("%lld",ans);
}

你可能感兴趣的:(前缀和,差分,nssl,1467,U)