小$C$在家中開墾了一塊菜地,能夠抽象成一個$r\times c$大小的矩形區域,菜地的每一個位置都種着一種蔬菜。秋天到了,小$C$家的菜地豐收了。
小$C$擬定了$q$種採摘蔬菜的計劃,計劃採摘區域是菜地的一個子矩形,你須要幫助他計算每種計劃的美味度,美味度等於每種蔬菜在採摘區域出現次數的平方和。html
第一行三個正整數$r,c,q$。
接下來$r$行每行$c$個正整數,第$i+1$行第$j$個數爲$a_i,j$,表示每一個位置的蔬菜種類。
接下來$q$行,每行$4$個正整數$x_0,y_0,x_1,y_1$表示採摘區域的左上角和右下角的位置。c++
輸出$q$行,每行一個整數,第$i$行的數表示第$i$組採摘計劃的答案。spa
樣例輸入:htm
3 4 8
1 3 2 1
1 3 2 4
1 2 3 4
1 1 2 2
1 1 2 1
1 1 3 4
1 1 1 1
2 2 3 3
2 2 3 4
1 1 3 3
2 4 3 4blog
樣例輸出:排序
8
4
38
1
8
12
27
4get
對於$100\%$的數據,$r,c\leqslant 200,q\leqslant 100,000,a_i,j\leqslant {10}^9$。
$\bullet Subtask\ 1(23pts):r,c\leqslant 100,q\leqslant 1,000$。
$\bullet Subtask\ 2(15pts):r,c\leqslant 100,q\leqslant 10,000$。
$\bullet Subtask\ 3(17pts):r,c\leqslant 200,q\leqslant 50,000$。
$\bullet Subtask\ 4(20pts):$蔬菜種類數不超過$200$。
$\bullet Subtask\ 5(25pts):$無特殊限制it
正解是四維偏序,說白了就是$CDQ$套$CDQ$。io
然而能夠用二維莫隊水,隊爺就是$NB$。class
推銷一波二維莫隊:二維莫隊(離線)。
對於可怕的數據範圍,直接離散化搞就行了。
說了二維莫隊就沒啥好說的了,在這裏就想再說三點:
$\alpha.$對於一個知識點,你比別人多學或者是早學不是錯;哪怕你是知道此次要考什麼,由於即使告訴別人用什麼解法,不會仍是不會;而對於有人說的認爲複雜度不對,也能夠歸結爲不會——$to$可愛的同桌。
$\beta.$這道題的數據有點水,因此打一個假的二維莫隊也能夠水過去,有的人知道,有的人不知道,在此提醒一下,這樣排序是不對的:
bool cmp(rec a,rec b){return (a.x0==b.x0)?((a.x2==b.x2)?((a.y0==b.y0)?a.y2<b.y2:a.y0<b.y0):a.x2<b.x2):a.x0<b.x0;}
可是的確能夠水過去,正確的方法應該是:
int sqrr=sqrt(r);sqrc=sqrt(c);
bool cmp(rec a,rec b){return a.x0/sqrr==b.x0/sqrr?(a.y0/sqrc==b.y0/sqrc?(a.x2/sqrr==b.x2/sqrr?a.y2/sqrc<b.y2/sqrc:a.x2<b.x2):a.y0<b.y0):a.x0<b.x0;}
$\gamma.$最好利用公式統計答案,即${x+1)}^2-x^2$,由於在種類過多的時候確定會卡死的。
時間複雜度:$\Theta(q\log q+q\times n\sqrt{n})$。
指望得分:$100$分。
實際得分:$100$分。
#include<bits/stdc++.h>
using namespace std;
struct rec{int x0,y0,x2,y2,pos,id;}e[100001];
int r,c,q;
int sqrr,sqrc;
int Map[201][201],zls;
int s[40001];
map<int,int> mp;
long long ans[100001];
int uu,dd,ll,rr;
bool cmp(rec a,rec b){return a.x0/sqrr==b.x0/sqrr?(a.y0/sqrc==b.y0/sqrc?(a.x2/sqrr==b.x2/sqrr?a.y2/sqrc<b.y2/sqrc:a.x2<b.x2):a.y0<b.y0):a.x0<b.x0;}
int ask(int x){return 2*x+1;}
void upd(int id,int l,int r,bool b,bool w){for(int i=l;i<=r;i++)if(b)if(w){ans[0]+=ask(s[Map[id][i]]);s[Map[id][i]]++;}else{s[Map[id][i]]--;ans[0]-=ask(s[Map[id][i]]);}else if(w){ans[0]+=ask(s[Map[i][id]]);s[Map[i][id]]++;}else{s[Map[i][id]]--;ans[0]-=ask(s[Map[i][id]]);}}
int main()
{
scanf("%d%d%d",&r,&c,&q);
sqrr=sqrt(r);sqrc=sqrt(c);
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
{
scanf("%d",&Map[i][j]);
if(!mp[Map[i][j]])Map[i][j]=mp[Map[i][j]]=++zls;
else Map[i][j]=mp[Map[i][j]];
}
for(int i=1;i<=q;i++)
{
scanf("%d%d%d%d",&e[i].x0,&e[i].y0,&e[i].x2,&e[i].y2);
e[i].id=i;
}
sort(e+1,e+q+1,cmp);
ll=rr=e[1].x0;
uu=dd=e[1].y0;
s[Map[ll][uu]]++;
ans[0]=1;
for(int i=1;i<=q;i++)
{
while(uu>e[i].y0)upd(--uu,ll,rr,0,1);
while(uu<e[i].y0)upd(uu++,ll,rr,0,0);
while(dd<e[i].y2)upd(++dd,ll,rr,0,1);
while(dd>e[i].y2)upd(dd--,ll,rr,0,0);
while(ll>e[i].x0)upd(--ll,uu,dd,1,1);
while(ll<e[i].x0)upd(ll++,uu,dd,1,0);
while(rr<e[i].x2)upd(++rr,uu,dd,1,1);
while(rr>e[i].x2)upd(rr--,uu,dd,1,0);
ans[e[i].id]=ans[0];
}
for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);
return 0;
}
rp++