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)的部分路径。
假设已经构成如图一棵树
![](https://img-blog.csdn.net/20160411214239179?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
要添加7这点。
假设已添加点集为{3,4,6},3与7存在一条边,那么显然添加7要添加这条边,如果是6与7存在一条边则是添加6与7边。要判断这一点就要有一个统一过程。首先计算7到最高点的路径长度(假设的一个深度小点),然后再加上前驱后继最近公共祖先u1到最高点的路径,再减去前驱,后继分别与7的最近公共祖先的路径,就能得到添加点7要增加的路径长度。(ps:证明说不明白0.0)
一开始觉得只要按照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网址
- 1272 小希的迷宫
- 1272 小希的迷宫
- hdu 1250 大数相加并用数组储存
- 矩阵的乘法操作
- 蚂蚁爬行问题
- 蚂蚁爬行问题
- 求两个数的最大公约数【ACM基础题】
- 打印出二进制中所有1的位置
- 杭电题目---一只小蜜蜂
- HDOJ 1002 A + B Problem II (Big Numbers Addition)
- 初学ACM - 半数集(Half Set)问题 NOJ 1010 / FOJ 1207
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1002
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points