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;
}