题意
给定一个n*m的方格,初始均为0,有以下三种操作:
1.给l-r行每个位置加x
2.给l列每个位置修改为x
3.询问x列y行的值
分析
我们考虑第q次询问的答案,是由上一次修改第y列的位置q',和q'-q次之间修改x行的和组成的
因为加x的操作可加减,所以这里不需要主席树,可以离线下来做一个用前缀差计算,维护树状数组即可
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n,m,q;
int opt[maxn],a[maxn],b[maxn],c[maxn];
int pos[maxn],cnt;
vector <int> del[maxn];
ll val[maxn],ans[maxn];
int lowbit(int x)
{
return x&(-x);
}
void modify(int pos,ll x)
{
while(pos<=m+1)
{
val[pos]+=x;
pos+=lowbit(pos);
}
}
ll query(int pos)
{
ll res=0;
while(pos)
{
res+=val[pos];
pos-=lowbit(pos);
}
return res;
}
int id[maxn],rev[maxn];
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=q;i++)
{
scanf("%d",&opt[i]);
if(opt[i]==1)
{
scanf("%d%d%d",&a[i],&b[i],&c[i]);
b[i]++;
}
if(opt[i]==2)
{
scanf("%d%d",&a[i],&c[i]);
pos[a[i]]=i;
}
if(opt[i]==3)
{
scanf("%d%d",&a[i],&b[i]);
swap(a[i],b[i]);
int x=c[pos[b[i]]];
ans[++cnt]=x;
id[i]=cnt; rev[cnt]=i;
del[pos[b[i]]].push_back(cnt);
}
}
// for(int i=1;i<=cnt;i++) printf("%lld\n",ans[i]);
for(int i=1;i<=q;i++)
{
if(opt[i]==1)
{
modify(a[i],c[i]);
modify(b[i],-c[i]);
}
if(opt[i]==2)
for(auto v:del[i]) ans[v]-=query(a[rev[v]]);
if(opt[i]==3)
ans[id[i]]+=query(a[i]);
}
for(int i=1;i<=cnt;i++) printf("%lld\n",ans[i]);
return 0;
}