http://acm.timus.ru/problem.aspx?space=1&num=1699

从一个点到另一个点正好有一条路 所以原图是一棵树

先求出每一对点的最近公共祖先lca

然后一遍dfs 求出每个点到它的lca的转弯数 最后还要判定两个点在lca处是否还要一个转弯

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<algorithm>
#include<cmath>
#define LL long long
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int INF=0x3f3f3f3f;
const int N=100005;
int head[N],I;
struct node
{
    int j,next;
    int k;
}edge[N*10];
int X[]={0,0,-1,1};
int Y[]={-1,1,0,0};
int K[]={1,1,2,2};
char grap[N];
bool visited[N];
int q1[N],q2[N],lca[N],d[N],prek[N],tok[N],k1[N],k2[N],ans[N];
int f[N];
vector<int>vt[N];
queue<int>qt;
int n,m;
void add(int i,int j,int k)
{
    edge[I].j=j;
    edge[I].k=k;
    edge[I].next=head[i];
    head[i]=I++;
}
void bfs(int s)
{
    memset(visited,false,sizeof(visited));
    visited[s]=true;
    qt.push(s);
    while(!qt.empty())
    {
        int x=qt.front();
        qt.pop();
        for(int i=0;i<4;++i)
        {
            int l1=x/m+X[i];
            int l2=x%m+Y[i];
            int st=x,nd=l1*m+l2;
            while(l1>=0&&l1<n&&l2>=0&&l2<m&&grap[nd]=='#'&&!visited[nd])
            {
                visited[nd]=true;
                qt.push(nd);
                add(st,nd,K[i]);
                st=nd;
                l1=l1+X[i];
                l2=l2+Y[i];
                nd=l1*m+l2;
            }
        }
    }
}
int fx(int x)
{
    if(f[x]!=x)
    f[x]=fx(f[x]);
    return f[x];
}
void findLca(int x)
{
    for(unsigned int i=0;i<vt[x].size();++i)
    {
        int l=vt[x][i];
        if(q1[l]==x)
        {
            if(f[q2[l]]!=-1)
            lca[l]=fx(q2[l]);
        }else
        {
            if(f[q1[l]]!=-1)
            lca[l]=fx(q1[l]);
        }
    }
}
void dfsLca(int x,int pre)
{
    f[x]=x;
    findLca(x);
    for(int t=head[x];t!=-1;t=edge[t].next)
    {
        int j=edge[t].j;
        dfsLca(j,x);
    }
    f[x]=pre;
}
void F(int x)
{
    for(unsigned int i=0;i<vt[x].size();++i)
    {
        int l=vt[x][i];
        int y=lca[l];
        if(x==q1[l])
        k1[l]=tok[y];
        else
        k2[l]=tok[y];
        ans[l]+=(d[x]-d[y]);
        if((prek[y]&tok[y])==0)
        --ans[l];
    }
}
void dfs(int x,int dt,int kt)
{
    d[x]=dt;
    prek[x]=kt;
    tok[x]=3;
    F(x);
    for(int t=head[x];t!=-1;t=edge[t].next)
    {
        int j=edge[t].j;
        tok[x]=edge[t].k;
        if((prek[x]&tok[x])==0)
        dfs(j,dt+1,edge[t].k);
        else
        dfs(j,dt,edge[t].k);
    }
}
int main()
{
    //freopen("data.in","r",stdin);
    cin>>n>>m;
    int s=-1;
    for(int i=0;i<n;++i)
    for(int j=0;j<m;++j)
    {
        cin>>grap[i*m+j];
        if(s==-1&&grap[i*m+j]=='#')
        s=i*m+j;
    }
    memset(head,-1,sizeof(head));
    I=0;
    bfs(s);
    int q;
    cin>>q;
    for(int i=0;i<q;++i)
    {
        int x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        --x1;--y1;--x2;--y2;
        q1[i]=x1*m+y1;
        q2[i]=x2*m+y2;
        if(q1[i]!=q2[i])
        vt[q1[i]].push_back(i);
        vt[q2[i]].push_back(i);
    }
    memset(f,-1,sizeof(f));
    dfsLca(s,s);
    for(int i=0;i<n*m;++i)
    vt[i].clear();
    for(int i=0;i<q;++i)
    if(q1[i]!=q2[i])
    {vt[q1[i]].push_back(i);vt[q2[i]].push_back(i);}
    memset(ans,0,sizeof(ans));
    dfs(s,0,3);
    for(int i=0;i<q;++i)
    {
        if(q1[i]==q2[i])
        {cout<<"0"<<endl;continue;}
        if((k1[i]&k2[i])==0)
        ++ans[i];
        cout<<ans[i]<<endl;
    }
    return 0;
}

  

posted on 2013-02-22 14:59  夜->  阅读(289)  评论(0编辑  收藏  举报