今天复习了下差分,发现还没写过差分的博客,便来写博客氵时间了.。
差分是啥不用多bb了,直接看简单用途吧。
差分思想的用途
差分数组适用于离线的区间修改问题,如果是在线,应该用线段树或其他数据结构。
(1)可以快速处理区间加减操作,并询问操作结束的每个元素的最新值。
(2)可以快速处理多次询问区间和问题。
利用差分数组求出M次处理后数组a[]每个元素的值,然后用O(N)的复杂度求出数组
a[]每个位置的前缀和sum[i],则区间[L,R]的和ans为sum[R]-sum[L-1]。
然后我知道的差分就三种,大体列一下吧。
一 一维数组数组差分
code:
for(int i=1;i<=n;i++) cin>>a[i]; //读入原始数据
while(m--)
{
int L,R,V;
cin>>L>>R>>V;
b[L]+=V;
b[R+1]-=V;
}
for(int i=1;i<=n;i++)
{
b[i]+=b[i-1]; //前缀和
a[i]+=b[i]; //合并
}
for(int i=1;i<=n;i++) cout<<a[i]<<" "; //输出操作后的结
cout<<endl;
return 0;
二 二维数组差分
code:
for (i=1; i<=n; i++) {
for (j=1; j<=m; j++) {
scanf("%d", &a[i][j]);
diff[i][j] = a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1];
}
}
for (i=0; i<q; i++) {
int x1, y1, x2, y2, c;
scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &c);
diff[x1][y1] += c;
diff[x1][y2+1] -=c;
diff[x2+1][y1] -=c;
diff[x2+1][y2+1] += c;
}
for (i=1; i<=n; i++) {
for (j=1; j<=m; j++) {
diff[i][j] += diff[i-1][j]+diff[i][j-1]-diff[i-1][j-1];
printf("%d ", diff[i][j]);
}
printf("\n");
}
return 0;
三 树上差分
树上差分呢则要分为两种,一是权值在点上
code:
for(int i=1;i<=m;i++)
{
x=Read(),y=Read();
val[x]+=1,val[y]+=1;
int saber=lca(x,y);
val[saber]-=1;
val[f[saber][0]]-=1;
}
void Find(int u,int fa)
{
for(int i=first[u];i;i=Next[i])
{
int v=to[i];
if(v==fa) continue;
Find(v,u);
val[u]+=val[v];
}
}
而当权值在边上时,我们则选择以每条边两端深度较大的节点存储该边的差分数组,只不过跟点差分有点区别
diff[u]+=x,diff[v]+=x,diff[o]-=2*x;//o是lca
其余都差不多。