2015多校第一场1009
题目意思是有一颗带边权的树,现在有个集合S,初始为空,有2种操作,把某个点加入S或者在S中删除,每次操作完后,都要你输出当前S集合中所有点相连的最小路径和。
设加入的点为u, 其实答案更新是 ans+ u点到S集合中最近的某条链的最短距离。删除点也是一样。
设dis[u]是u点到根节点的距离,lca(x,y)是x,y最近公共祖先。那么有一个点u到一条链x-y距离公式 dis[u]-dis[lca(x,u)]-dis[lca(y,u)]+dis[lca(x,y)]
证明 大概是 假设点u 到 链 x-y
那么u点 到x点 距离表示为 dis[u]+dis[x]-2dis[lca(x,u)]
那么u点 到y点 距离表示为 dis[u]+dis[y]-2dis[lca(y,u)]
然后u点到x-y链其实是上面走得距离 多走了 x到y的距离
即是dis[x]+dis[y]-2dis[lca(y,x)]
相减 便 是u到链x-y距离 ,注意算了2次。
关键找最小距离。
首先把DFS序处理出来,每次加点就是找DFS序比这个点小 中最大那个,和DFS序比这个点大最小的那个
如果找不就,就直接找DFS序最大 和最小的点。
通过上面所讲,计算更新即可。
代码如下:
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<set>
using namespace std;
const int NN=100010;
struct node
{
int en;
int next;
int len;
}E[2*NN];
int p[NN],num;
int deep[NN];
int fa[NN][21];
int dis[NN];
void init()
{
memset(p,-1,sizeof(p));
num=0;
memset(deep,-1,sizeof(deep));
memset(fa,0,sizeof(fa));
memset(dis,0,sizeof(dis));
}
void add(int st,int en,int len)
{
E[num].en=en;
E[num].next=p[st];
E[num].len=len;
p[st]=num++;
}
int tid[NN];//对应dfs序编号
int L[NN],R[NN];//以i为根的子树开始和结束。
int time;
void dfs(int x)//初始化deep[x]=1,time=0;
{
tid[x]=++time;
// L[x]=id;
for(int i=p[x];i+1;i=E[i].next)
{
int v=E[i].en;
if(deep[v]<0)
{
deep[v]=deep[x]+1;
dis[v]=dis[x]+E[i].len;
fa[v][0]=x;
dfs(v);
}
}
// R[x]=id;
}
void get_fa(int n)
{
for(int j=1;j<20;j++)
{
for(int i=1;i<=n;i++)
{
fa[i][j]=fa[fa[i][j-1]][j-1];
}
}
}
int LCA(int u,int v)
{
if(deep[u]<deep[v])
swap(u,v);
for(int i=19;i>=0;i--)
{
if(deep[fa[u][i]]>=deep[v])
u=fa[u][i];
if(deep[u]==deep[v])
break;
}
if(u==v)
return u;
for(int i=19;i>=0;i--)
{
if(fa[u][i]!=fa[v][i])
{
u=fa[u][i];
v=fa[v][i];
}
}
return fa[u][0];
}
set< pair<int,int> >myset;
int main()
{
int T,ca=0;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d %d",&n,&m);
init();
for(int i=1;i<n;i++)
{
int u,v,len;
scanf("%d %d %d",&u,&v,&len);
add(u,v,len);
add(v,u,len);
}
deep[1]=1;
time=0;
dfs(1);
get_fa(n);
myset.clear();
int ans=0;
printf("Case #%d:\n",++ca);
while(m--)
{
int op,u;
scanf("%d %d",&op,&u);
if(op==1)
{
if(myset.find(make_pair(tid[u],u))!=myset.end())
{
printf("%d\n",ans);
continue;
}
set< pair<int,int> >::iterator it;
it=myset.upper_bound(make_pair(tid[u],u));
if(myset.size()==0)
myset.insert(make_pair(tid[u],u));
else
{
int x,y;
if(it==myset.end())
{
it--;
y=it->second;
x=myset.begin()->second;
}
else if(it==myset.begin())
{
x=it->second;
it=myset.end();
it--;
y=it->second;
}
else
{
y=it->second;
it--;
x=it->second;
}
myset.insert(make_pair(tid[u],u));
ans+=dis[u]-dis[LCA(u,x)]-dis[LCA(u,y)]+dis[LCA(x,y)];
}
printf("%d\n",ans);
}
else
{
if(myset.find(make_pair(tid[u],u))==myset.end())
{
printf("%d\n",ans);
continue;
}
myset.erase(make_pair(tid[u],u));
set< pair<int,int> >::iterator it;
it=myset.upper_bound(make_pair(tid[u],u));
if(myset.size()!=0)
{
int x,y;
if(it==myset.end())
{
it--;
y=it->second;
x=myset.begin()->second;
}
else if(it==myset.begin())
{
x=it->second;
it=myset.end();
it--;
y=it->second;
}
else
{
y=it->second;
it--;
x=it->second;
}
ans-=dis[u]-dis[LCA(u,x)]-dis[LCA(u,y)]+dis[LCA(x,y)];
}
printf("%d\n",ans);
}
}
}
return 0;
}