[国家集训队]矩阵乘法

整体二分

关于整体二分的资料比较少,这里简单提一下思路。在此时,如果 \(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.
posted @ 2018-09-23 09:22  _ARFA  阅读(152)  评论(0编辑  收藏  举报