1176: [Balkan2007]Mokia
Time Limit: 30 Sec
Memory Limit: 162 MB
Submit: 1922
Solved: 846
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=200005;
int o[N],a[N],b[N],c[N],d[N],s,w,n,cc[N*10],ans[N];
struct pp{int x,y,num,p;}Mo[N],Qu[N];
bool cmp(pp u,pp v)
{
if(u.y!=v.y) return u.y<v.y;
return u.x<v.x;
}
void Modify(int x,int v)
{
for(;x<=w;x+=(x&-x)) cc[x]+=v;
}
int Query(int x)
{
if(x==0) return 0;
int tmp=0;
for(;x;x-=(x&-x)) tmp+=cc[x];
return tmp;
}
void solve(int l,int r)
{
if(l>=r) return;
int mid=(l+r)>>1,mo=0,qu=0;
for(int i=l;i<=mid;i++)
if(o[i]==1) Mo[++mo]=(pp){a[i],b[i],0,c[i]};
for(int i=mid+1;i<=r;i++)
if(o[i]==2)
{
Qu[++qu]=(pp){a[i]-1,b[i]-1,i,1};
Qu[++qu]=(pp){a[i]-1,d[i],i,-1};
Qu[++qu]=(pp){c[i],b[i]-1,i,-1};
Qu[++qu]=(pp){c[i],d[i],i,1};
}
sort(Mo+1,Mo+mo+1,cmp);
sort(Qu+1,Qu+qu+1,cmp);
int j=1;
for(int i=1;i<=mo;i++)
{
int tmp=Mo[i].y;
while(Qu[j].y<tmp&&j<=qu) ans[Qu[j].num]+=Query(Qu[j].x)*Qu[j].p,j++;
if(j>qu) break;
while(Mo[i].y==tmp&&i<=mo) Modify(Mo[i].x,Mo[i].p),i++;
i--;
}
for(;j<=qu;j++) ans[Qu[j].num]+=Query(Qu[j].x)*Qu[j].p;
for(int i=1;i<=mo;i++) Modify(Mo[i].x,-Mo[i].p);
solve(l,mid),solve(mid+1,r);
}
int main()
{
scanf("%d%d",&s,&w);
n=1;
while(scanf("%d",&o[n])!=EOF)
{
if(o[n]==1) scanf("%d%d%d",&a[n],&b[n],&c[n]);
else if(o[n]==2) scanf("%d%d%d%d",&a[n],&b[n],&c[n],&d[n]);
else break;
n++;
}
solve(1,n);
for(int i=1;i<=n;i++)
if(o[i]==2) printf("%d\n",ans[i]);
}
Description
维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.
Input
第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小
接下来每行为一下三种输入之一(不包含引号):
"1 x y a"
"2 x1 y1 x2 y2"
"3"
输入1:你需要把(x,y)(第x行第y列)的格子权值增加a
输入2:你需要求出以左上角为(x1,y1),右下角为(x2,y2)的矩阵内所有格子的权值和,并输出
输入3:表示输入结束
Output
对于每个输入2,输出一行,即输入2的答案
Sample Input
0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
Sample Output
3
5
5
HINT
保证答案不会超过int范围