描述
一個方陣,支持單點修改,查詢一個小矩陣的和。
思路
蒟蒻並不會樹套樹,但最近學了點CDQ分治的皮毛,做了一下這道題。
對於修改直接記錄。
對於查詢拆成四部分。
類似於矩陣前綴和,運用查分的思想。
ans=1+2-3-4;
然後cdq中維護x升序。以y爲下標維護樹狀數組。
記錄左區間修改,修改右區間的查詢。
代碼
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1000000+10;
struct node
{
int val,type,tag,x,y;
bool operator < (const node &o) const
{
if(x!=o.x) return x<o.x;
else if(y!=o.y) return y<o.y;
else return type<o.type;
}
}a[maxn],b[maxn],tt[maxn];
int n,m,tot,totx,ans[maxn];
int tree[maxn];
int lowbit(int x)
{
return x&(-x);
}
void modify(int x,int d)
{
while(x<=n)
{
tree[x]+=d;
x+=lowbit(x);
}
}
int query(int x)
{
int ans=0;
while(x)
{
ans+=tree[x];
x-=lowbit(x);
}
return ans;
}
void cdq(int l,int r)
{
if(l==r) return;
int mid=(l+r)>>1;
cdq(l,mid); cdq(mid+1,r);
int p1=l,p2=mid+1,cnt=0;
for(int i=l; i<=r; i++)
{
if((p1<=mid && a[p1]<a[p2]) || p2>r)
{
if(a[p1].type==1)
{
cnt++; tt[cnt]=a[p1]; modify(a[p1].y,a[p1].val);
}
b[i]=a[p1]; p1++;
}
else
{
if(a[p2].type==2)
{
ans[a[p2].val]+=a[p2].tag*query(a[p2].y);
}
b[i]=a[p2]; p2++;
}
}
for(int i=l; i<=r; i++) a[i]=b[i];
for(int i=1; i<=cnt; i++)
{
modify(tt[i].y,-tt[i].val);
}
}
int main()
{
freopen("locust.in","r",stdin);
freopen("locust.out","w",stdout);
scanf("%d %d",&n,&m);
while(m--)
{
int opt;
scanf("%d",&opt);
if(opt==1)
{
int x,y,w; scanf("%d %d %d",&x,&y,&w);
tot++; a[tot].type=1; a[tot].x=x; a[tot].y=y;
a[tot].val=w;
}
else
{
int xx,yy,x2,y2; totx++;
scanf("%d %d %d %d",&xx,&yy,&x2,&y2);
//拆成四部分,建議畫一下圖
tot++; a[tot]=(node){totx,2,1,x2,y2};
tot++; a[tot]=(node){totx,2,1,xx-1,yy-1};
tot++; a[tot]=(node){totx,2,-1,xx-1,y2};
tot++; a[tot]=(node){totx,2,-1,x2,yy-1};
}
}
cdq(1,tot);
for(int i=1; i<=totx; i++)
{
printf("%d\n",ans[i]);
}
return 0;
}