您的位置:首页 > 其它

hdu4916 Count on the path

2014-08-09 19:48 363 查看
 2014 Multi-University Training Contest 5 F题。

题目大意:给定一颗n个节点的树,q个查询,每次查询输入两个端点(u,v),代表树上一条从u->v的路径,求删掉这条路径上的点后,剩下的点中编号最小的点。

题目分析:可以这样想象:(1)我们以1这个节点为根,删掉根节点后形成若干个联通分量,很显然若路径中的两个端点在删掉根节点后还在同一个联通分量中,那么所求结果必然为1。这个可在预处理后O(1)实现(2)若两个端点不在同一个联通分量中,那么必然经过根节点,此时若纯暴力则时间复杂度可达O(n*q)之大,题目数据量非常大,必然死掉。 官方的题解给了做题的方向,可以用树形DP的思想,预处理求出每个节点的f[]值,f[u]代表从u到他所属的根节点(删除1之后的)除去路径上的点后编号最小的点值。

如下图所示,所求的值f[2]=4,f[3]=7,f[4]=5,f[5]=6,f[7]=8,f[8]=7,f[9]=8;

2所对应的根节点为2,f[2]=min(与2同属于一个联通分量且不在2到根节点的链上的,2以下的节点中编号最小的);

求出所有的f[]值后,还需知道各个联通分量中编号最小的点,因为当根节点1的儿子节点有多个,即有多个联通分量时 ,两个端点分属两个联通分量,最小值可能出现在别的联通分量中,但f[]值没有考虑到。 则我们需要保存编号最小的三个联通分量。

比较绕口,过后补上图解。





#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#include<queue>
struct node
{
int u,parent;
node(){}
node(int x,int y)
{
u=x,parent=y;
}
};
using namespace std;
const int maxn = 1000010;
stack<int  >S;
queue<node >Q;
int pp[maxn];
int n,q,ecnt=0;
int next[maxn*2],e[maxn*2],head[maxn];
int cnt[maxn],f[maxn],x[5],y[5],other[maxn];
void addedge(int u,int v)
{
e[ecnt]=v;
next[ecnt]=head[u];
head[u]=ecnt++;
e[ecnt]=u;
next[ecnt]=head[v];
head[v]=ecnt++;
}
void dfs(int u,int fa)
{
f[u]=fa;
S.push(u);
while (!S.empty())
{
u=S.top();
int flag=0;
for (int i=head[u];i!=-1;i=next[i])
{
int v=e[i];
if (!f[v])
{
f[v]=fa;
S.push(v);
flag=1;
break;
}
}
if (!flag)
{
S.pop();
if (!S.empty())
{
int v=u;
u=S.top();
cnt[u]=min(v,cnt[u]);
cnt[u]=min(cnt[u],cnt[v]);
}
}
}
}
void bfs(int u,int parent)
{
Q.push(node(u,parent));
while (!Q.empty())
{
int x1=n+1,x2=n+1,y1=n+1,y2=n+1;
node tem=Q.front();
Q.pop();
u=tem.u;
parent=tem.parent;
for (int i=head[u];i!=-1;i=next[i])
{
int v=e[i];
if (v!=parent)
{
Q.push(node(v,u));
int yy=min(cnt[v],v);
if (yy<y1)
{
y2=y1;
x2=x1;
y1=yy;
x1=v;
}
else if (yy<y2)
{
y2=yy;
x2=v;
}
}
}
for (int i=head[u];i!=-1;i=next[i])
{
int v=e[i];
if (v==u)
continue;
other[v]=other[u];
if (v!=x1)
{
other[v]=min(other[v],y1);
}
else
{
other[v]=min(other[v],y2);
}
}
}
return ;
}
inline void scan(int &n)
{
char cc;
for (; cc = getchar(), cc<'0' || cc>'9';);
n = cc - '0';
for (; cc = getchar(), cc >= '0'&&cc <= '9';)
n = n * 10 + cc - '0';
}
int main()
{
while (scanf("%d%d",&n,&q)!=EOF)
{
int i,j,u,v,prex=0;
ecnt=0;
for (i=1;i<=n;i++)
{
head[i]=-1;
f[i]=0;
cnt[i]=n+1;
other[i]=n+1;
}
for (i=1;i<n;i++)
{
//            scanf("%d%d",&u,&v);
scan(u);
scan(v);
addedge(u,v);
}
f[1]=1;
cnt[1]=n+1;
x[0]=x[1]=x[2]=0;
y[0]=y[1]=y[2]=n+1;
for (i=head[1];i!=-1;i=next[i])
{
dfs(e[i],e[i]);
}
for (i=head[1];i!=-1;i=next[i])
{
bfs(e[i],1);
int fa=min(cnt[e[i]],e[i]);
if (fa<y[0])
{
y[2]=y[1];
y[1]=y[0];
y[0]=fa;
x[2]=x[1];
x[1]=x[0];
x[0]=e[i];
}
else if (fa<y[1])
{
y[2]=y[1];
y[1]=fa;
x[2]=x[1];
x[1]=e[i];
}
else if (fa<y[2])
{
y[2]=fa;
x[2]=e[i];
}
}
for (i=2;i<=n;i++)
{
cnt[i]=min(other[i],cnt[i]);
}
for (i=0;i<q;i++)
{
//            scanf("%d%d",&u,&v);
scan(u);
scan(v);
u^=prex;
v^=prex;
if (f[u]==f[v]&&(u!=1&&v!=1))
{
printf("1\n");
prex=1;
}
else
{
int tot=min(cnt[u],cnt[v]);
if (tot>y[0]&&(x[0]!=f[u]&&x[0]!=f[v]))
{
tot=y[0];
}
else if (tot>y[1]&&(x[1]!=f[u]&&x[1]!=f[v]))
{
tot=y[1];
}
else if (tot>y[2])
{
tot=y[2];
}
prex=tot;
printf("%d\n",tot);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息