[国家集训队]矩阵乘法
整体二分
关于整体二分的资料比较少,这里简单提一下思路。在此时,如果 \(A\) 个修改在此个查询之内,那么如果 \(A\) 大于这个查询的 \(K\),那么这个询问的答案肯定在 \(A\) 里面 (在左边),否则肯定不在 \(A\) 里面(在右边)。这样子我们就把询问划分到了左右两边,那么修改也按自己的数来划分成左右两边。划分到了右边,要让这个查询的 \(K\) 减去 \(A\) ,原因就是你已经到了右边,你的答案(某一次修改)肯定也在右边,不过在右边时就变成了第 \(K-A\) 大。
略丑。
Uses math;
var
ans:array[-1..580000] of longint;
copy1,copy2,num:array[-1..580000,1..6] of longint;
tree:array[-1..510,-1..510] of longint;
i,j,n,m,x1,y1,x2,y2,k,cnt,maxn:longint;
function lowbit(x:longint):longint; begin exit(x and -x); end;
procedure Insertx(x,y,k:longint); begin while y<=n do begin inc(tree[x,y],k); inc(y,lowbit(y)); end; end;
procedure Insert(x,y,k:longint); begin while x<=n do begin Insertx(x,y,k); inc(x,lowbit(x)); end; end;
function Sumx(x,y:longint):longint; begin Sumx:=0; while y>0 do begin inc(Sumx,tree[x,y]); dec(y,lowbit(y)); end; end;
function Sum(x,y:longint):longint; begin Sum:=0; while x>0 do begin inc(Sum,Sumx(x,y)); dec(x,lowbit(x)); end; end;
function Query(x1,y1,x2,y2:longint):longint; begin exit(Sum(x2,y2)-Sum(x1-1,y2)-Sum(x2,y1-1)+Sum(x1-1,y1-1)); end;
procedure Add(a,b,c,d,e,f:longint); begin inc(cnt); num[cnt,1]:=a; num[cnt,2]:=b; num[cnt,3]:=c; num[cnt,4]:=d; num[cnt,5]:=e; num[cnt,6]:=f; end;
procedure Divid(l,r,left,right:longint);
var
mid,tmp,i,j,i1:longint;
tot:array[1..2] of longint;
begin
if (l>r)or(left>right) then exit;
if l=r then
begin for i:=left to right do if num[i,6]>0 then ans[num[i,6]]:=l; exit;
end;
mid:=(l+r) >> 1; tot[1]:=0; tot[2]:=0;
for i:=left to right do
begin
if num[i,6]>0 then
begin
tmp:=Query(num[i,1],num[i,2],num[i,3],num[i,4]);
if tmp>=num[i,5] then begin
inc(tot[1]); copy1[tot[1]]:=num[i];
end else begin
dec(num[i,5],tmp); inc(tot[2]); copy2[tot[2]]:=num[i];
end;
end
else
begin
if num[i,5]<=mid then begin
inc(tot[1]); copy1[tot[1]]:=num[i]; Insert(num[i,1],num[i,2],1);
end else begin
inc(tot[2]); copy2[tot[2]]:=num[i];
end;
end;
end;
for i:=1 to tot[1] do if copy1[i,6]=0 then Insert(copy1[i,1],copy1[i,2],-1);
for i:=1 to tot[1] do num[left+i-1]:=copy1[i];
for i:=1 to tot[2] do num[left+tot[1]+i-1]:=copy2[i];
Divid(l,mid,left,left+tot[1]-1);
Divid(mid+1,r,left+tot[1],right);
end;
begin
read(n,m);
for i:=1 to n do for j:=1 to n do begin read(k); maxn:=max(maxn,k); Add(i,j,0,0,k,0); end;
for i:=1 to m do begin read(x1,y1,x2,y2,k); Add(x1,y1,x2,y2,k,i); end;
Divid(0,maxn+1,1,cnt);
for i:=1 to m do writeln(ans[i]);
end.
完结撒花!✿✿ヽ(゚▽゚)ノ✿