 /**//*
題意:問海平面為d時,各個島嶼的income總和
首先要注意d高于格子的高度時,未必被掩了,跟相鄰有關。
方法就是類似最短路的先對所有的點重新標號,得到每個點真正被淹沒的時間。
用PQ的dijkstra 我用spfa好像有問題,應該我寫得有問題
像數據 33333
35553
35153
35553
33333
之后就是對查詢排序,然后從高到低,看那些格子升出了水面,這些格子可能會和周圍的格子練成島嶼,
這個部分通過并查集來做就好了。
用map<int, int>來記錄大小為first的島嶼有second個,以回答查詢。

細節很多
如:
應該合并到較高位置;
要先查詢、每個點高度排序,對每次查詢都掃描是否已經合并過就TLE了
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>

using namespace std;

const int MAXN = 510;

 const int dx[4]= {0,0,1,-1};
 const int dy[4]= {1,-1,0,0};

int R,C,Q;
long long ans[10010];
int height[MAXN][MAXN];
bool visit[MAXN][MAXN];
int fa[MAXN*MAXN],S[MAXN*MAXN];
map<int,int>mp;

 bool chk(int x,int y) {return x>=0&&x<R&&y>=0&&y<C;}

 /**//*
計算1的個數 也可以遞推
ones[0]=0
for(int i=1;i<MAXN*MAXN;i++)
ones[i]=ones[i>>1]+(i&1);
*/
inline int calc(int x)
  {
int tot=0;
while(x)tot+=(x&1),x>>=1;
return tot;
}
int find(int x)
  {
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void unit(int x,int y)
  {
x=find(x),y=find(y);
if(x==y)return;
if(--mp[S[x]]==0)mp.erase(S[x]);//注意刪除掉!
if(--mp[S[y]]==0)mp.erase(S[y]);
fa[x]=y;
S[y]+=S[x];
mp[S[y]]++;
}
int main()
  {
while(~scanf("%d%d",&R,&C))
 {
mp.clear();
memset(visit,0,sizeof(visit));
priority_queue<pair<int,pair<int,int> > >PQ;
for(int i=0;i<R;i++)
for(int j=0;j<C;j++)
 {
scanf("%d",&height[i][j]);
if(i==R-1||i==0||j==C-1||j==0)
 {
visit[i][j]=1;
PQ.push(make_pair(-height[i][j],make_pair(i,j)));
}
}
//dijkstra
while(!PQ.empty())
 {
int x=PQ.top().second.first,y=PQ.top().second.second;
PQ.pop();
for(int k=0;k<4;k++)
 {
int xx=x+dx[k],yy=y+dy[k];
if(chk(xx,yy)&&!visit[xx][yy])
 {
visit[xx][yy]=1;//第一次遇到的就是答案了
height[xx][yy]=max(height[xx][yy],height[x][y]);
PQ.push(make_pair(-height[xx][yy],make_pair(xx,yy)));
}
}
}

 /**//*
for(int i=0;i<R;i++)
for(int j=0;j<C;j++)
{
printf("%d%c",height[i][j],j==C-1?'\n':' ');
}
*/

scanf("%d",&Q);
vector<pair<int,pair<int,int> > > VQ,VT;
VQ.resize(Q);//
for(int i=0;i<Q;i++)
 {
scanf("%d%d",&VQ[i].first,&VQ[i].second.first);
VQ[i].second.second=i;
}
for(int i=0;i<R;i++)
for(int j=0;j<C;j++)
 {
fa[i*C+j]=i*C+j;
S[i*C+j]=1;
VT.push_back(make_pair(height[i][j],make_pair(i,j)));
}

//按照查詢的d排序從大到小查詢
//然后VT也排序一下,這樣就不需多次合并了 用一個指針走下去就行了!
sort(VQ.begin(),VQ.end());
sort(VT.begin(),VT.end());

memset(visit,0,sizeof(visit));
vector<pair<int,pair<int,int> > >::reverse_iterator itQ=VQ.rbegin(),itT=VT.rbegin();
for(;itQ!=VQ.rend();itQ++)
 {
int d=itQ->first,A=itQ->second.first,id=itQ->second.second;
while(itT!=VT.rend()&&itT->first>d)//
 {
int x=itT->second.first,y=itT->second.second;
visit[x][y]=1;
mp[1]++;
for(int k=0;k<4;k++)
 {
int xx=x+dx[k],yy=y+dy[k];
//向高處(visit[,]=1)合并
if(chk(xx,yy)&&visit[xx][yy])unit(xx*C+yy,x*C+y);
}
itT++;
}
ans[id]=0;
for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++)
 {
ans[id]+=it->second*(1LL<<calc(it->first&A));
}
}
for(int i=0;i<Q;i++)
printf("%lld\n",ans[i]);
}
return 0;
}
|
|
常用鏈接
隨筆分類
Links
搜索
最新評論

|
|