您的位置:首页 > 其它

第十二周 11.16---11.22

2015-11-16 22:45 281 查看
新的一周>_<

---------11.16

补题--

越来越觉得笨得可以了--

----------11.17

补了南阳最短路那题

那样的转化还是不是很懂---

---- wo shi sb----

---------11.18

补了南阳的 修乒乓器室,台球室那题dp

全程看题解---还是觉得理解得好艰难啊--

---------11.19

补了多校第一场的一道题

hdu 5296

给出一棵树,然后有2个操作

1 x 是将 x 节点 加入 集合 中

2 x 是将 x 节点从集合中删除

为了使集合中的任意两个点都是联通的,至少需要加的边权

-----没有思路-----------------

看的题解了

假设一条链的两端 是 x 和 y ,一个节点 u

u 到 链 x---y 的距离大概是这样来算的

u 到 x 端的距离 dis[u] + dis[x] - 2dis[Lca(x,u)]

u 到 y 端的距离 dis[u] + dis[y] - 2dis[Lca(y,u)]

多算了 x 到 y 的距离 dis[x] + dis[y] - 2dis[Lca(x,y)]

所以 u 到 链 x --- y 的距离为

{ dis[u] + dis[x] - 2dis[Lca(x,u)] + dis[u] + dis[y] - 2dis[Lca(y,u)] - dis[x] + dis[y] - 2dis[Lca(x,y)]}/2

然后,就是x,y端的选择

题解说根据 dfn 来选

选择节点 u 左边和右边挨得最近 的 x ,y

如果没找到的话,就分别是 最小的,最大的

可是为什么是这样,,,,

画了几下,貌似这样的距离是更小的,,,,

自己先用的set的lower_bound 和 upper_bound来找 左右两边的

可是写搓了

后来看了别人的代码

发现是漏了 在 添加操作的时候,那个节点本来就在集合里面

在删除的时候,那个节点本来就不在集合里面

这两种情况

然后,,还学到了 set的重载,从大到小的放元素,直接找不到就是 到 了 set.end()

感觉比自己这样一边找到 begin(),一边找到 end 方便些

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
using namespace std;

typedef long long LL;
const int MAXN = 4e5+5;
const int MAX_LOG = 32;
int n,q,ecnt,tot;
int first[MAXN],dfn[MAXN],ddfn[MAXN];
int fa[MAX_LOG][MAXN],dep[MAXN];
int dis[MAXN];

struct Edge{
int u,v,nxt,w;
}e[MAXN];

void init(){
memset(first,-1,sizeof(first));
ecnt = tot = 0;
}

void Add_edge(int u,int v,int w){
e[ecnt].u = u;
e[ecnt].v = v;
e[ecnt].w = w;
e[ecnt].nxt = first[u];
first[u] = ecnt++;
}

void Dfs(int p,int pre,int d){
dfn[p] = ++tot;
ddfn[tot] = p;
dep[p] = d;
fa[0][p] = pre;
for(int i = first[p];~i;i = e[i].nxt){
int v = e[i].v;
if(v == pre) continue;
dis[v] = dis[p] + e[i].w;
Dfs(v,p,d+1);
}
}

void Pre(){
dis[1] = 0;
Dfs(1,-1,0);
for(int k = 0;k+1 < MAX_LOG;++k){
for(int v = 1;v <= n;++v){
if(fa[k][v] < 0) fa[k+1][v] = -1;
else fa[k+1][v] = fa[k][fa[k][v]];
}
}
}

int Lca(int u,int v){
if(dep[u] > dep[v]) swap(u,v);
for(int k = MAX_LOG-1;k >= 0;--k){
if((dep[v]-dep[u]) & (1<<k)) v = fa[k][v];
}
if(u == v) return u;
for(int k = MAX_LOG-1;k >= 0;--k){
if(fa[k][u] != fa[k][v]){
u = fa[k][u];
v = fa[k][v];
}
}
return fa[0][u];
}

void solve(){
set<int> s;
set<int>::iterator l,it,r,itt;

int ans = 0,x,y;
for(int i = 1;i <= q;i++){
int cmd,u;
scanf("%d %d",&cmd,&u);
if(cmd == 1){
if(s.size() == 0){
puts("0");
s.insert(dfn[u]);
continue;
}
if(s.find(dfn[u]) != s.end()){
printf("%d\n",ans);
s.insert(dfn[u]);
continue;
}
l = s.lower_bound(dfn[u]);
r = s.upper_bound(dfn[u]);
if(l == s.begin() || r == s.end()){
l = s.begin();r = s.end();r--;
}
else l--;
x = ddfn[*l];y = ddfn[*r];
// printf("x = %d  y = %d\n",x,y);
ans += dis[u] - dis[Lca(x,u)] - dis[Lca(u,y)] + dis[Lca(x,y)];
printf("%d\n",ans);
s.insert(dfn[u]);
}
else{
if(s.find(dfn[u]) == s.end()){
printf("%d\n",ans);
continue;
}
s.erase(dfn[u]);
if(s.size() == 0){
puts("0");
continue;
}
l = s.lower_bound(dfn[u]);
r = s.upper_bound(dfn[u]);
if(l == s.begin() || r == s.end()){
l = s.begin();r = s.end();r--;
}
else l--;
x = ddfn[*l];y = ddfn[*r];
ans -= dis[u] - dis[Lca(x,u)] - dis[Lca(u,y)] + dis[Lca(x,y)];
printf("%d\n",ans);
}
}
}

int main(){
int T;
scanf("%d",&T);
int kase = 0;
while(T--){
init();
scanf("%d %d",&n,&q);
for(int i = 1;i <= n-1;i++){
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
Add_edge(u,v,w);
Add_edge(v,u,w);
}
Pre();
printf("Case #%d:\n",++kase);
solve();
}
return 0;
}


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