现在的位置: 首页 > 综合 > 正文

矩形计算(钟沛林)

2017年11月17日 ⁄ 综合 ⁄ 共 6211字 ⁄ 字号 评论关闭

http://www.tsinsen.com/ViewGProblem.html?gpid=-1000001310

问题描述
  输入一个n*m的矩阵,矩阵的每一个元素都是一个整数,然后有q个询问,每次询问一个子矩阵的权值。矩阵的权值是这样定义的,对于一个整数x,如果它在该矩阵中出现了p次,那么它给该矩阵的权值就贡献p2
输入格式
  第一行两个整数n,m表示矩阵的规模。
  接下来n行每行m个整数,表示这个矩阵的每个元素。
  再下来一行一个整数q,表示询问个数。
  接下来q行每行四个正整数x1,y1,x2,y2,询问以第x1行第y1列和第x2行第y2列的连线为对角线的子矩阵的权值。
输出格式
  输出q行每行一个整数回答对应询问。
样例输入
3 4
1 3 2 1
1 3 2 4
1 2 3 4
8
1 2 2 1
1 1 2 1
1 1 3 4
1 1 1 1
2 2 3 3
3 4 2 2
1 3 3 1
2 4 3 4
样例输出
8
4
38
1
8
12
27
4
数据规模和约定

  对于全部数据
  1<=n,m<=200
  q<=100000
  |矩阵元素大小|<=2*109

case1 3 3
-1 1 2
-1 -1 1
10 2 1
3
1 3 3 1
1 3 2 2
2 1 3 2
case2 n<=10,m<=10,q<=100000  
case3 n<=100,m<=100,q<=5000  
case4 n<=200,m<=200,q<=1000  
case5 n<=200,m<=200,q<=1000  
case6 n<=200,m<=200,q<=1000  
case7 n<=100,m<=100,q<=50000 原矩阵中的不同元素不超过200
case8 n<=100,m<=100,q<=50000 原矩阵中的不同元素不超过200
case9 n<=100,m<=100,q<=50000 原矩阵中的不同元素不超过200
case10 n<=200,m<=200,q<=100000 原矩阵中的不同元素不超过200
case11 n<=200,m<=200,q<=100000 原矩阵中的不同元素不超过200
case12 n<=200,m<=200,q<=100000 原矩阵中的不同元素不超过200
case13 n<=100,m<=100,q<=100000  
case14 n<=100,m<=100,q<=100000  
case15 n<=200,m<=200,q<=100000  
case16 n<=200,m<=200,q<=100000  
case17 n<=200,m<=200,q<=100000  
case18 n<=200,m<=200,q<=100000  
case19 n<=200,m<=200,q<=100000  
case20 n<=200,m<=200,q<=100000  

首先考虑颜色少于200种的解法

对于每种颜色开一个n*m的矩阵,f[i,j]表示以(1,1)为左上角,(i,j)为右下角的举行中包含这种颜色的有多少个

这样就可以在O(1)的时间内求出来一个举行中有该种颜色多少个了

设颜色种类为c,复杂度为O(cq)

颜色多了自然不可解……

如何解决呢

假设有一个划分标准p

在矩阵中出现次数多于p次的颜色按上面的做法来做,那么回答一次询问的复杂度为n*m/p

少于的我们采用另外一种做法

一个矩阵里一种颜色的出现次数的平方等于以两个相同颜色的点为顶点形成的在询问的矩形里的矩形个数

所以可以预先把这些矩形生成出来,查询当前矩形包含多少个矩形

矩形个数最多为n*m/p*p^2=nmp个

查询矩形内有多少个矩形,满足的条件为x1<=x1i,x2i<=x2,y1<=y1i,y2i<=y2

这个可以用四维树状数组来求

但是四维树状数组复杂度为log^4 n,这道题又不存在修改,询问之间也没有关系

所以可以离线来做,按询问x1从大到小来回答询问,然后按x1从大到小来插入矩形,这样用三维树状数组即可完成

(为什么不用线段树……因为线段树空间复杂度为(2n)^3,常数还较大……会爆空间)

至此,这道题完全解决,虽然复杂度算下来要超时,但实际上是跑得过的……

顺道一提,这个颜色少于200种用这个方法跑的比较慢……直接用最初的方法就好了

我的p取值为sqrt((n*m+q)/2)

{$inline on}
program t2;
type
  node=record
         x1,x2,y1,y2:longint;
       end;
const
  maxn=400001;

var
  w:longint;
  o,sum,p,all,tot,n,m,i,j,k,q,x1,y1,x2,y2,u,v:longint;
  num,count,new:array [0..40001] of longint;
  map:array [0..201,0..201] of longint;
  quick:array [0..401,0..201,0..201] of longint;
  tree:array [0..201,0..201,0..201] of longint;
  ans:array [0..100001] of longint;
  dl:array [0..100001] of longint;
  que:array [0..100001] of node;
  four:array [0..maxn] of node;
  x,y:array [0..40001] of longint;

procedure swap (var a,b:longint);inline;
begin
  if a=b then exit;
  b:=a xor b;
  a:=a xor b;
  b:=a xor b;
end;

procedure disp;

  procedure qsort (s,e:longint);
  var
    i,j,k:longint;
  begin
    if s>=e then exit;
    i:=s;
    j:=e;
    k:=dl[(s+e) div 2];
    while i<=j do
      begin
        while dl[i]<k do inc(i);
        while dl[j]>k do dec(j);
        if i>j then break;
        swap(dl[i],dl[j]);
        inc(i);
        dec(j);
      end;
    qsort(s,j);
    qsort(i,e);
  end;

begin
  qsort(1,tot);
  all:=0;
  i:=1;
  while i<=tot do
    begin
      k:=i;
      while dl[i]=dl[k] do inc(i);
      inc(all);
      new[all]:=dl[k];
    end;
end;

procedure renum;inline;

  function convert (now:longint):longint;inline;
  var
    mid,s,e:longint;
  begin
    s:=1;
    e:=all;
    while s<>e do
      begin
        mid:=(s+e) div 2;
        if new[mid]<now then s:=mid+1
                        else e:=mid;
      end;
    exit(s);
  end;

begin
  for i:=1 to n do
    for j:=1 to m do
      begin
        map[i,j]:=convert(map[i,j]);
        inc(count[map[i,j]]);
      end;
end;

procedure case1;inline;
var
  ans,w:longint;
begin
  tot:=0;
  for i:=1 to all do
    if count[i]>=p then
      begin
        inc(tot);
        for j:=1 to n do
          for k:=1 to m do
            begin
              quick[tot,j,k]:=quick[tot,j-1,k]
                             +quick[tot,j,k-1]
                             -quick[tot,j-1,k-1];
              if map[j,k]=i then inc(quick[tot,j,k]);
            end;
      end;
  if p<>0 then exit;
  read(q);
  for i:=1 to q do
    begin
      read(x1,y1,x2,y2);
      if x1>x2 then swap(x1,x2);
      if y1>y2 then swap(y1,y2);
      ans:=0;
      for k:=1 to tot do
        begin
          w:=quick[k,x2,y2]
            -quick[k,x1-1,y2]
            -quick[k,x2,y1-1]
            +quick[k,x1-1,y1-1];
          ans:=ans+w*w;
        end;
      writeln(ans);
    end;
  halt;
end;

procedure case2;

  procedure qsort (s,e:longint);
  var
    i,j,k:longint;
  begin
    if s>=e then exit;
    i:=s;
    j:=e;
    k:=map[x[(s+e) div 2],y[(s+e) div 2]];
    while i<=j do
      begin
        while map[x[i],y[i]]<k do inc(i);
        while map[x[j],y[j]]>k do dec(j);
        if i>j then break;
        swap(x[i],x[j]);
        swap(y[i],y[j]);
        inc(i);
        dec(j);
      end;
    qsort(s,j);
    qsort(i,e);
  end;

  procedure qsort1 (s,e:longint);
  var
    i,j,k:longint;

    procedure swap (var a,b:node);inline;
    var
      i:node;
    begin
      i:=a;
      a:=b;
      b:=i;
    end;

  begin
    if s>=e then exit;
    i:=s;
    j:=e;
    k:=four[(s+e) div 2].x1;
    while i<=j do
      begin
        while four[i].x1<k do inc(i);
        while four[j].x1>k do dec(j);
        if i>j then break;
        swap(four[i],four[j]);
        inc(i);
        dec(j);
      end;
    qsort1(s,j);
    qsort1(i,e);
  end;

begin
  o:=0;
  for i:=1 to n do
    for j:=1 to m do
      if count[map[i,j]]<p then
        begin
          inc(o);
          x[o]:=i;
          y[o]:=j;
        end;
  qsort(1,o);
  sum:=0;
  i:=1;
  while i<=o do
    begin
      k:=i;
      while (i<=o)and(map[x[i],y[i]]=map[x[k],y[k]]) do inc(i);
      for u:=k to i-1 do
        for v:=k to i-1 do
          begin
            x1:=x[u];
            y1:=y[u];
            x2:=x[v];
            y2:=y[v];
            if x1>x2 then swap(x1,x2);
            if y1>y2 then swap(y1,y2);
            inc(sum);
            four[sum].x1:=x1;
            four[sum].x2:=x2;
            four[sum].y1:=y1;
            four[sum].y2:=y2;
          end;
    end;
  qsort1(1,sum);
end;

procedure question;

  procedure qsort (s,e:longint);
  var
    i,j,k:longint;
  begin
    if s>=e then exit;
    i:=s;
    j:=e;
    k:=dl[(s+e) div 2];
    while i<=j do
      begin
        while que[dl[i]].x1<que[k].x1 do inc(i);
        while que[dl[j]].x1>que[k].x1 do dec(j);
        if i>j then break;
        swap(dl[i],dl[j]);
        inc(i);
        dec(j);
      end;
    qsort(s,j);
    qsort(i,e);
  end;

begin
  read(q);
  for i:=1 to q do
    begin
      read(x1,y1,x2,y2);
      if x1>x2 then swap(x1,x2);
      if y1>y2 then swap(y1,y2);
      que[i].x1:=x1;
      que[i].x2:=x2;
      que[i].y1:=y1;

      que[i].y2:=y2;
      dl[i]:=i;
    end;
  qsort(1,q);
end;

function lowbit (x:longint):longint;inline;
begin
  exit(x and (x xor (x-1)));
end;

procedure insert (x2,y1,y2:longint);
var
  i,j,k:longint;
begin
  i:=x2;
  while i<=n do
    begin
      j:=y1;
      while j<=m do
        begin
          k:=y2;
          while k<=m do
            begin
              inc(tree[i,j,k]);
              k:=k+lowbit(k);
            end;
          j:=j+lowbit(j);
        end;
      i:=i+lowbit(i);
    end;
end;

function find (x2,y1,y2:longint):longint;
var
  ans:longint;
  i,j,k:longint;
begin
  ans:=0;
  i:=x2;
  while i>0 do
    begin
      j:=m;
      while j>0 do
        begin
          k:=y2;
          while k>0 do
            begin
              ans:=ans+tree[i,j,k];
              k:=k-lowbit(k);
            end;
          j:=j-lowbit(j);
        end;
      j:=y1-1;
      while j>0 do
        begin
          k:=y2;
          while k>0 do
            begin
              ans:=ans-tree[i,j,k];
              k:=k-lowbit(k);
            end;
          j:=j-lowbit(j);
        end;
      i:=i-lowbit(i);
    end;
  exit(ans);
end;

procedure solve;
begin
  k:=sum;
  for i:=q downto 1 do
    begin
      x1:=que[dl[i]].x1;
      x2:=que[dl[i]].x2;
      y1:=que[dl[i]].y1;
      y2:=que[dl[i]].y2;
      for j:=1 to tot do
        begin
          w:=quick[j,x2,y2]
            -quick[j,x1-1,y2]
            -quick[j,x2,y1-1]
            +quick[j,x1-1,y1-1];
          ans[dl[i]]:=ans[dl[i]]+w*w;
        end;
      while (k>0)and(four[k].x1>=x1) do
        begin
          insert(four[k].x2,four[k].y1,four[k].y2);
          dec(k);
        end;
      w:=find(x2,y1,y2);
      ans[dl[i]]:=ans[dl[i]]+w;
    end;
end;

begin
  read(n,m);
  for i:=1 to n do
    for j:=1 to m do
      begin
        read(map[i,j]);
        inc(tot);
        dl[tot]:=map[i,j];
      end;
  disp;
////////////////////////////////////////////
  renum;
////////////////////////////////////////////
  if all<=200 then p:=0
              else p:=trunc(sqrt((n*m+q))/2);
  case1;
  case2;
////////////////////////////////////////////
  question;
////////////////////////////////////////////
  solve;
////////////////////////////////////////////
  for i:=1 to q do
    writeln(ans[i]);
end.

抱歉!评论已关闭.