Contest20140709 testA 树型DP
testA
输入文件:
testA.in 输出文件testA.out
时限5000ms
问题描述:
一棵树N个节点,每条边有一个距W,现在定义SUM为所有dist(X,Y)的和1<=X<Y<=N
,
dist(X,Y)表示X到Y在树上的距离。现在给你一个机会把任意一条边删掉,再把这条边连接其他两个节点使得SUM最小。求出SUM的最小值
输入描述:
第一行N。
第二行到第N行每行三个数X,Y,W。表示X到Y有一条长度为W的边。
。
输出描述:
一行一个数表示答案。
数据范围N<=5000 , W<=10^6
样例输入1:
6
1
2 1
2 3 1
3 4 1
4 5 1
5 6 1
样例输出1:
29
样例输入2:
3
1
2 2
1 3 4
样例输出2:
12
就因为这道题卡了我很久啊。总之就是维护一堆乱七八糟的值。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 10000
#define MAXE MAXN*2
#define MAXV MAXN
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
typedef long long qword;
int n,m;
struct edge
{
int x,y;
}el[MAXE];
struct Edge
{
int np,val;
int id;
Edge *next;
}E[MAXE],*V[MAXV];
int root,tope=-;
void addedge(int x,int y,int z,int id)
{
E[++tope].np=y;
E[tope].next=V[x];
E[tope].val=z;
E[tope].id=id;
V[x]=&E[tope];
}
int fa[MAXN];
int dis_fa[MAXN];
int q[MAXN];
int ope=-,clo=;
int dp1[MAXN];//size of subtree
qword dp2[MAXN];//the total distance from each child to the root in subtree
qword dp3[MAXN];//the total distance from each node outside the subtree to root
qword dp4[MAXN];//the total distance of each pair
void bfs(int root)
{
ope=-,clo=;
Edge *ne;
q[]=root;
fa[root]=;
int now;
while (ope<clo)
{
now=q[++ope];
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==fa[now])continue;
fa[ne->np]=now;
dis_fa[ne->np]=ne->val;
q[++clo]=ne->np;
}
}
}
qword work1()
{
int i,j;
Edge *ne;
int now;
for (i=clo;i>=;i--)
{
now=q[i];
dp1[now]=;
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==fa[now])continue;
dp1[now]+=dp1[ne->np];
}
}
for (i=clo;i>=;i--)
{
now=q[i];
dp2[now]=;
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==fa[now])continue;
dp2[now]+=dp2[ne->np]+dp1[ne->np]*ne->val;
}
}
dp3[q[]]=;
for (i=;i<=clo;i++)
{
now=q[i];
// dp3[now]=dp3[fa[now]]+dp2[fa[now]]-dp2[now]+dis_fa[now]*(-dp1[now]+dp1[fa[now]]-dp1[now]);
dp3[now]=dp3[fa[now]]+dp2[fa[now]]-dp2[now]-dis_fa[now]*dp1[now]+dis_fa[now]*(dp1[root]-dp1[now]);
}
qword ret=;
for (i=;i<=n;i++)
{
ret+=(qword)dis_fa[i]*dp1[i]*(dp1[root]-dp1[i]);
}
return ret;
}
bool edge_st[MAXN];
int color[MAXN];
qword dist[MAXN];
void dfs2(int now,int fat,int col,qword d)
{
color[now]=col;
dist[now]=d;
Edge *ne;
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==fat)continue;
dfs2(ne->np,now,col,d+ne->val);
}
}
int main()
{
freopen("testA.in","r",stdin);
//freopen("testA.out","w",stdout);
int i,j,k;
int x,y,z;
scanf("%d",&n);
for (i=;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z,i-);
addedge(y,x,z,i-);
el[i-].x=x;
el[i-].y=y;
}
m=n-;
root=;
bfs(root);
qword sum_old=work1();
//cout<<"SUM_OLD:"<<sum_old<<endl;
qword dis1,dis2;
qword dis_old1,dis_old2;
qword mus1,mus2;
int totm1,totm2;
qword best=;
for (i=;i<m;i++)
{
edge_st[i]=;
if (fa[el[i].x]==el[i].y)swap(el[i].x,el[i].y);
dfs2(el[i].x,el[i].y,,);//1:outside
dfs2(el[i].y,el[i].x,,);//2:inside
dis_old1=dp3[el[i].y]-dis_fa[el[i].y]*(dp1[root]-dp1[el[i].y]);
dis_old2=dp2[el[i].y];
mus1=dp2[el[i].y]+dp1[el[i].y]*dis_fa[el[i].y];
mus2=dp3[el[i].y];
totm1=dp1[el[i].y];
totm2=dp1[root]-dp1[el[i].y];
dis1=dis2=INF;
for (j=;j<=n;j++)
{
if (color[j]==)
{
dis2=min(dis2,dp2[j]+dp3[j]-mus2-totm2*dist[j]);
}else
{
dis1=min(dis1,dp2[j]+dp3[j]-mus1-totm1*dist[j]);
}
}
best=max(best,(dis_old1-dis1)*totm1+(dis_old2-dis2)*totm2);
}
printf(LL "\n",sum_old-best);
return ;
}
Contest20140709 testA 树型DP的更多相关文章
- POJ3659 Cell Phone Network(树上最小支配集:树型DP)
题目求一棵树的最小支配数. 支配集,即把图的点分成两个集合,所有非支配集内的点都和支配集内的某一点相邻. 听说即使是二分图,最小支配集的求解也是还没多项式算法的.而树上求最小支配集树型DP就OK了. ...
- POJ 3342 - Party at Hali-Bula 树型DP+最优解唯一性判断
好久没写树型dp了...以前都是先找到叶子节点.用队列维护来做的...这次学着vector动态数组+DFS回朔的方法..感觉思路更加的清晰... 关于题目的第一问...能邀请到的最多人数..so ea ...
- 【XSY1905】【XSY2761】新访问计划 二分 树型DP
题目描述 给你一棵树,你要从\(1\)号点出发,经过这棵树的每条边至少一次,最后回到\(1\)号点,经过一条边要花费\(w_i\)的时间. 你还可以乘车,从一个点取另一个点,需要花费\(c\)的时间. ...
- 洛谷P3354 Riv河流 [IOI2005] 树型dp
正解:树型dp 解题报告: 传送门! 简要题意:有棵树,每个节点有个权值w,要求选k个节点,最大化∑dis*w,其中如果某个节点到根的路径上选了别的节点,dis指的是到达那个节点的距离 首先这个一看就 ...
- 【POJ 3140】 Contestants Division(树型dp)
id=3140">[POJ 3140] Contestants Division(树型dp) Time Limit: 2000MS Memory Limit: 65536K Tot ...
- Codeforces 581F Zublicanes and Mumocrates(树型DP)
题目链接 Round 322 Problem F 题意 给定一棵树,保证叶子结点个数为$2$(也就是度数为$1$的结点),现在要把所有的点染色(黑或白) 要求一半叶子结点的颜色为白,一半叶子结点的 ...
- ZOJ 3949 (17th 浙大校赛 B题,树型DP)
题目链接 The 17th Zhejiang University Programming Contest Problem B 题意 给定一棵树,现在要加一条连接$1$(根结点)和$x$的边,求加 ...
- BZOJ 1564 :[NOI2009]二叉查找树(树型DP)
二叉查找树 [题目描述] 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小. 另一方面,这棵查找树中每个结点都有一个权值,每个结 ...
- Codeforces 149D Coloring Brackets(树型DP)
题目链接 Coloring Brackets 考虑树型DP.(我参考了Q巨的代码还是略不理解……) 首先在序列的最外面加一对括号.预处理出DFS树. 每个点有9中状态.假设0位不涂色,1为涂红色,2为 ...
随机推荐
- linux内存管理系列 +CFS 图解
http://blog.chinaunix.net/uid-20543183-id-1930786.html http://blog.csdn.net/ustc_dylan/article/categ ...
- 设计模式——工厂模式 (C++实现)
软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径.设计模式中运用了面向对象编程语言的重要特性:封装.继承.多态,真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积累. ...
- Android(java)学习笔记169:Activity中的onCreate()方法分析
1.onCreate( )方法是android应用程序中最常见的方法之一: 翻译过来就是说,onCreate()函数是在activity初始化的时候调用的,通常情况下,我们需要在onCreate()中 ...
- 可变字典 NSMutableDictionary
存到nsuesrDefault里面一个可变字典,然后用一个可变字典去接收. NSMutableDictionary *dic = [[NSUserDefaults standardUserDefaul ...
- linux下实现redis共享session的tomcat集群
为了实现主域名与子域名的下不同的产品间一次登录,到处访问的效果,因此采用rediss实现tomcat的集群效果.基于redis能够异步讲缓存内容固化到磁盘上,从而当服务器意外重启后,仍然能够让sess ...
- apache日志介绍
apache日志介绍: 通用日志格式: CommonLogFormat 组合日志格式: CombinedLogFormat 例如: <VirtualHost *: ...
- JVM体系结构
为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/SJQ. http://www.cnblogs.com/shijiaqi1066/p/5187049.html ...
- Angular2 - Starter - Component and Component Lifecircle Hooks
我们通过一个NgModule来启动一个ng app,NgModule通过bootstrap配置来指定应用的入口组件. @NgModule({ bootstrap: [ AppComponent ], ...
- mysql left用法
LEFT(str,len) 返回字符串str的最左面len个字符. SELECT LEFT('123456789',5)
- Jsp内置对象-session
session内置对象介绍 个人理解:session因为是唯一的, session是与请求有关的会话期,它是java.servlet.http.HttpSession类的对象,用来表示和存储当前页面的 ...