您的位置:首页 > 其它

[2015hdu多校联赛补题]hdu5296 Annoying problem

2015-08-02 21:55 337 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5296

题意:给你一棵n个结点的边权树和一个树上点的集合,开始时集合为空

然后进行两种操作:

1、如果结点u不在集合中,那么将u加入集合

2、如果结点u在集合中,那么删除u

每次操作后输出包含点集合的最小联通子图的边权和

题解:

其实问题的本质就是求结点u与子图的距离(如果在子图内部距离为0),yy一下可以想到,若x、y为集合中与u最近的两点,那么dis(u,子图)=dis(u,联通u、x、y三点的汇点)

问题转化为求x、y,将树上结点以dfs序重标号,如果u在点集标号集的外侧,那么x、y分别为点集标号集的最大标号与最小标号,如果在内侧,那么x、y分别为u的左右

然后求u与 联通u、x、y三点汇点 的距离:

dis(u,联通u、x、y三点的汇点)=(dis(u,x)+dis(u,y)+dis(x,y))/2-dis(x,y)

dis(a,b)=dfn[a] +dfn[b] -2dfn[lca(a,b)] (lca和dfn都是求树链长度用到的东西,lca(a,b):a、b的最近公共祖先,dfn[x]:根结点到x的路径的边权和)

/*
* Problem:
* Author:  SHJWUDP
* Created Time:  2015/8/2 星期日 15:20:01
* File Name: 233.cpp
* State:
* Memo:
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>

using namespace std;

struct Edge {
int u, v, w;
Edge(int u, int v, int w):u(u), v(v), w(w){}
};

int n, q;
vector<Edge> edges;
vector<vector<int> > G;
vector<int> pos, id, dep, dfn;
vector<vector<int> > fa;
set<int> S;
int root, cnt;
void init(int sz) {
edges.clear();
G.assign(sz, vector<int>(0));
S.clear();
pos.resize(sz);
id.resize(sz);
dep.resize(sz);
dfn.resize(sz);
fa.assign(sz, vector<int>(20));
}
void addEdge(int u, int v, int w) {
edges.push_back(Edge(u, v, w));
G[u].push_back(edges.size()-1);
}
void dfs(int u) {
pos[u]=++cnt;
id[cnt]=u;
for(int k=1; k<20; k++) {
fa[u][k]=fa[fa[u][k-1]][k-1];
}
for(int i : G[u]) {
Edge & e=edges[i];
if(e.v==fa[u][0]) continue;
dfn[e.v]=dfn[u]+e.w;
dep[e.v]=dep[u]+1;
fa[e.v][0]=u;
dfs(e.v);
}
}
int lca(int u, int v) {
if(dep[u]<dep[v]) swap(u, v);
for(int k=19; k>=0; k--) {
if(dep[fa[u][k]]>=dep[v]) {
u=fa[u][k];
}
}
if(u==v) return u;
for(int k=19; k>=0; k--) {
if(fa[u][k]!=fa[v][k]) {
u=fa[u][k]; v=fa[v][k];
}
}
return fa[u][0];
}
int func(int u) {
int res=0;
if(!S.empty()) {
auto it=S.lower_bound(pos[u]);
int x, y;
if(it==S.begin() || it==S.end()) {
x=id[*S.begin()];
y=id[*S.rbegin()];
} else {
x=id[*it];
y=id[*--it];
}
res=dfn[u]-dfn[lca(u, x)]-dfn[lca(u, y)]+dfn[lca(x, y)];
}
return res;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in", "r", stdin);
//freopen("out", "w", stdout);
#endif
int T, now=0;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &q);
init(n+1);
for(int i=0; i<n-1; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
addEdge(a, b, c);
addEdge(b, a, c);
}
root=1; cnt=0; fa[root][0]=root; dep[root]=0; dfn[root]=0; dfs(root);
printf("Case #%d:\n", ++now);
int ans=0;
while(q--) {
int op, u;
scanf("%d%d", &op, &u);
auto it=S.find(pos[u]);
if(op==1 && it==S.end()) {
ans+=func(u);
S.insert(pos[u]);
} else if(op==2 && it!=S.end()) {
S.erase(it);
ans-=func(u);
}
printf("%d\n", ans);
}
}
return 0;
}


hdu 5296
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: