POJ 1984
题意:有多个点,在平面上位于坐标点上,给出一些关系,表示某个点在某个点的正东/西/南/北方向多少距离,然后给出一系列询问,表示在第几个关系给出后询问某两点的曼哈顿距离,或者未知则输出-1。
做法:x,y左边分别两个权值做权值并查集后,对所有询问强制离线,按询问时间戳排序,处理答案即可。(类似莫队之类的)
#include <iostream> #include <algorithm> #include <stdio.h> #include <string.h> using namespace std; int pre[40100]; int xsum[40100]; int ysum[40100]; int n,m,k; int ans[40100]; struct node { int x,y; int dx,dy; }edge[40010]; struct enode { int x,y; int id; int pos; }q[40010]; bool cmp(struct enode a, struct enode b) { return a.id<b.id; } int f(int x) { if(x==pre[x]) return pre[x]; int fx=pre[x]; pre[x]=f(pre[x]); xsum[x]+=xsum[fx]; ysum[x]+=ysum[fx]; return pre[x]; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) { pre[i]=i; xsum[i]=0; ysum[i]=0; } char s; for(int i=1;i<=m;++i) { int d,dx,dy; scanf("%d %d %d %c",&edge[i].x,&edge[i].y,&d,&s) ; if(s=='N') {dx=0, dy=d;} else if(s=='E') {dx=d, dy=0;} else if(s=='S') {dx=0, dy=-d;} else if(s=='W') {dx=-d, dy=0;} edge[i].dx=dx; edge[i].dy=dy; } scanf("%d",&k); for(int i=1;i<=k;++i) { scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].id); q[i].pos=i; } sort(q+1,q+1+k,cmp); int now=0; for(int i=1;i<=k;++i) { while(now!=q[i].id) { now+=1; if(now>m) break; int lx=edge[now].x,ly=edge[now].y; int flx=f(lx), fly=f(ly); pre[fly]=flx; xsum[fly]=xsum[lx]-xsum[ly]-edge[now].dx; ysum[fly]=ysum[lx]-ysum[ly]-edge[now].dy; } int qx=q[i].x,qy=q[i].y; if(f(qx)!=f(qy)) { ans[q[i].pos]=-1; } else { ans[q[i].pos]=abs(xsum[qx]-xsum[qy])+abs(ysum[qx]-ysum[qy]); } } for(int i=1;i<=k;++i) { printf("%d\n",ans[i]); } return 0; }
POJ 1414
题意:给出p1+p2个人,其中p1个是好人,p2个是坏人。然后有一些关系 ,a说b是好人(坏人).其中没有矛盾的,判断是否有唯一解判断哪些人是好人,哪些人是坏人。其中比较重要的是,好人总说真话,坏人总说假话。不需要判断矛盾。唯一解
注意:如果说yes 那么两个人一定同类,no不同类
做法:先用关系并查集把所有人分成若干个以某个人为首的大集合,其中包含两个小集合 第一个表示与根节点同类,第二个表示与根节点异类。然后dp dp[i][j] 表示前i 个大集合 好人有j的情况数。(同时记录路径),如果最后一个集合的p1个人只有一种那么说明有答案。(也可以用母函数枚举根节点是好人还是坏人)
#include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> #include <vector> using namespace std; const int maxn=630; int q,p1,p2; int pre[maxn]; int sum[maxn]; int dp[maxn][maxn]; int path[maxn][maxn]; int num[maxn][2]; vector<int> who[maxn][2]; bool vis[maxn]; int f(int x) { if(x==pre[x]) return pre[x]; int fx=pre[x]; pre[x]=f(pre[x]); sum[x]=(sum[x]+sum[fx])%2; return pre[x]; } int main() { while(scanf("%d%d%d",&q,&p1,&p2)!=EOF) { if(q==0&&p1==0&&p2==0) break; for(int i=0;i<maxn;++i) { sum[i] = 0; pre[i]=i; vis[i]=0; } for(int i=1;i<=q;++i) { int x,y; char s[10]; scanf("%d%d%s",&x,&y,s); int temp; if(s[0]=='n') temp = 1; else temp = 0; int fx=f(x) , fy=f(y); if(fy!=fx) { pre[fy]=fx; sum[fy]=(sum[x]-temp-sum[y]+4)%2; } } for(int i=0;i<maxn;++i) { who[i][0].clear(); who[i][1].clear(); num[i][0]=0; num[i][1]=0; } int cnt=1; for(int i=1;i<=(p1+p2);++i) { if(vis[i]==0) { int fx=f(i); for(int j=1;j<=(p1+p2);++j) { if(f(j)==fx) { vis[j]=1; who[cnt][sum[j]].push_back(j); num[cnt][sum[j]]++; } } cnt++; } } memset(dp,0,sizeof(dp)); dp[0][0]=1; for(int i=1;i<cnt;++i) { for(int j=p1;j>=0;--j) { if(j>=num[i][0] && dp[i-1][j-num[i][0]]) { dp[i][j] += dp[i-1][ j-num[i][0] ]; path[i][j] = j-num[i][0]; } if(j>=num[i][1] && dp[i-1][j-num[i][1]]) { dp[i][j] += dp[i-1][j-num[i][1]]; path[i][j] = j-num[i][1] ; } } } if(dp[cnt-1][p1]!=1) { printf("no\n"); } else { vector<int> ans; ans.clear(); int much=p1; for(int i=cnt-1;i>=1;--i) { int pep= much - path[i][much] ; if(pep==num[i][0]) { for(int j=0;j<num[i][0] ; ++j ) ans.push_back(who[i][0][j]); } else { for(int j=0;j<num[i][1]; ++j) ans.push_back(who[i][1][j]); } much = path[i][much] ; } sort(ans.begin() , ans.end()); for(int i=0;i<ans.size();++i) { printf("%d\n",ans[i]); } printf("end\n"); } } return 0; }