您的位置:首页 > 其它

HYSBZ 3991 寻宝游戏(lca)

2016-04-11 21:41 337 查看
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3991

一开始觉得只要按照lca来添加点就好了,结果错了,后来想到没那么简单。

所以关键如何维护这棵树。

对于一个新添加的点u,想要知道要添加的路径可以先查询在虚树中dfs序前驱点,后继点,因为当这点添加进树时,肯定是要添加Lca(前驱,u)或Lca(后继,u)的部分路径。

假设已经构成如图一棵树

要添加7这点。

假设已添加点集为{3,4,6},3与7存在一条边,那么显然添加7要添加这条边,如果是6与7存在一条边则是添加6与7边。要判断这一点就要有一个统一过程。首先计算7到最高点的路径长度(假设的一个深度小点),然后再加上前驱后继最近公共祖先u1到最高点的路径,再减去前驱,后继分别与7的最近公共祖先的路径,就能得到添加点7要增加的路径长度。(ps:证明说不明白0.0)

/**************************************************************
Problem: 3991
User: q437634645
Language: C++
Result: Accepted
Time:8360 ms
Memory:43760 kb
****************************************************************/

/*--------------------------------------------------------
Author:log
Created Time:2016年03月20日 星期日 09时24分05秒
--------------------------------------------------------*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>

using namespace std;

#define ll long long
#define iter set<int>::iterator

const int maxn=100005;
const int maxj=20;

struct Edge{
int to,ne;
ll v;
}e[maxn<<1];
int head[maxn];
ll st[maxn<<1][maxj];
int dfn[maxn],dfn_cot;
ll depth[maxn];
set<int>s;
ll ans;

void dfs(int u,int fa){
st[dfn[u]=++dfn_cot][0]=depth[u];
for(int i=head[u];~i;i=e[i].ne)if(e[i].to!=fa){
depth[e[i].to]=depth[u]+e[i].v;
dfs(e[i].to,u);
st[++dfn_cot][0]=depth[u];
}
}
void init(int n){
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
ll query(int l,int r){
int k=0;
while((1<<(k+1))<(r-l+1))k++;
return min(st[l][k],st[r-(1<<k)+1][k]);
}
iter pre(iter it){
iter temp=it;
return --temp;
}
iter nxt(iter it){
iter temp=it;
return ++temp;
}
void add(int dfnx){
iter it;
it=s.insert(dfnx).first;
ans+=st[dfnx][0];
if(s.size()==1)return ;
if(it==s.begin()){
ans-=query(*it,*nxt(it));
return ;
}
if(nxt(it)==s.end()){
ans-=query(*pre(it),*it);
return ;
}
ans+=query(*pre(it),*nxt(it));
ans-=query(*pre(it),*it);
ans-=query(*it,*nxt(it));
return ;
}
void del(int dfnx){
iter it;
it=s.find(dfnx);
ans-=st[dfnx][0];
if(s.size()==1){
s.erase(it);
return ;
}
if(it==s.begin()){
ans+=query(*it,*nxt(it));
s.erase(it);
return ;
}
if(nxt(it)==s.end()){
ans+=query(*pre(it),*it);
s.erase(it);
return ;
}
ans-=query(*pre(it),*nxt(it));
ans+=query(*pre(it),*it);
ans+=query(*it,*nxt(it));
s.erase(it);
return ;
}
int cot;
void addedge(int u,int v,int d){
e[cot].to=v;
e[cot].v=d;
e[cot].ne=head[u];
head[u]=cot++;
}
ll lca(){
if(s.size()==0)return 0LL;
return query(*s.begin(),*pre(s.end()));
}
bool vis[maxn];

int main(){
int n,m;
scanf("%d %d",&n,&m);
int u,v;
ll d;
memset(head,-1,sizeof(head));
cot=0;
ans=0;
for(int i=0;i<n-1;i++){
scanf("%d %d %lld",&u,&v,&d);
addedge(u,v,d);
addedge(v,u,d);
}
dfs(1,0);
init(dfn_cot);
for(int i=0;i<m;i++){
scanf("%d",&u);
if(vis[u]){vis[u]=0;del(dfn[u]);}
else {vis[u]=1;add(dfn[u]);}
printf("%lld\n",(ans-lca())<<1);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm lca dfs序