/**//* 题意:问海平面为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
搜索
最新评论
|
|