Contest 高数题 樹的點分治 樹形DP
高数题
HJA最近在刷高数题,他遇到了这样一道高数题。这道高数题里面有一棵N个点的树,树上每个点有点权,每条边有颜色。一条路径的权值是这条路径上所有点的点权和,一条合法的路径需要满足该路径上任意相邻的两条边颜色都不相同。问这棵树上所有合法路径的权值和是多少
输入第一行一个整数N,代表树上有多少个点。
接下来一行N个整数,代表树上每个点的权值。
接下来N-1行,每行三个整数S、E、C,代表S与E之间有一条颜色为C的边。输出一行一个整数,代表所求的值。样例输入
6
6 2 3 7 1 4
1 2 1
1 3 2
1 4 3
2 5 1
2 6 2
样例输出
134
提示
对与30%的数据,1≤N≤1000。
对于另外20%的数据,可用的颜色数不超过109且随机数据。
对于另外20%的数据,树的形态为一条链。
对于100%的数据,1≤N≤3*105,可用的颜色数不超过109,所有点权的大小不超过105。
這道題簡單的說是一個樹形DP,由下至上分別統計路徑條數,而考場上我想都沒想就開始寫樹的點分治,當天狀態不佳,加之本身的不熟練,沒能按時把點分治寫出來。
唯一需要注意的是n=3*10^5,dfs足以使程序崩掉,以後最好改寫bfs
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<string>
#include<queue>
#include<stack>
using namespace std;
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
#define MAXN 410000
#define MAXV MAXN*2
#define MAXE MAXV*2
#define INF 0x3f3f3f3f
#define PROB "gaoshu"
typedef long long qword;
int nextInt()
{
char ch;
int x=;
while (ch=getchar(),ch < '' || ch > '' );
// cout<<ch;
do
x=x*+ch-'';
while (ch=getchar(),ch<='' && ch>='');
return x;
}
int n;
struct Edge
{
int np,col;
int val;
pair<qword,qword> val2;
Edge *next,*neg;
int disable;
}E[MAXE],*V[MAXV];
qword val[MAXN];
int tope=-;
int bad[MAXN][];
int size[MAXN];
//int fa[MAXN],depth[MAXN];
//int jump[20][MAXN]; void addedge(int x,int y,int z)
{
// cout<<"Add:"<<x<<" "<<y<<endl;
E[++tope].np=y;
E[tope].col=z;
E[tope].next=V[x];
V[x]=&E[tope]; E[++tope].np=x;
E[tope].col=z;
E[tope].next=V[y];
V[y]=&E[tope]; E[tope].neg=&E[tope-];
E[tope-].neg=&E[tope];
}
/*
void dfs1(int now,int d)
{
size[now]=1;depth[now]=d;
Edge *ne;
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==fa[now])continue;
fa[ne->np]=now;
dfs1(ne->np,d+1);
size[now]+=size[ne->np];
}
}
void init_lca()
{
int i,j;
for (i=1;i<=n;i++)
{
jump[0][i]=fa[i];
}
for (j=1;j<20;j++)
{
for (i=1;i<=n;i++)
{
jump[j][i]=jump[j-1][jump[j-1][i]];
}
}
}
void swim(int &now,int len)
{
int i=0;
while (len)
{
if (len&1)now=jump[i][now];
i++;
}
}
int lca(int x,int y)
{
if (depth[x]>depth[y])
{
swim(x,depth[x]-depth[y]);
}else
{
swim(y,depth[y]-depth[x]);
}
int i;
if (x==y)return x;
for (i=19;i>=0;i--)
{
if (jump[i][x]!=jump[i][y])
{
x=jump[i][x];
y=jump[i][y];
}
}
return fa[x];
}*/
int bcore,vcore;
int size2[MAXN];
int get_core_sizt;
int gc_sizf[MAXN];
int gc_mxsz[MAXN];
int gc_col[MAXN];
int gc_now[MAXN];
Edge *nel[MAXN];
int get_core(int dep=)
{
gc_sizf[dep]=get_core_sizt-;
gc_mxsz[dep]=;
size2[gc_now[dep]]=;
for (nel[dep]=V[gc_now[dep]];nel[dep];nel[dep]=nel[dep]->next)
{
if (nel[dep]->np==gc_now[dep-] || nel[dep]->disable)continue;
gc_col[dep+]=nel[dep]->col;
gc_now[dep+]=nel[dep]->np;
get_core(dep+);
size2[gc_now[dep]]+=size2[nel[dep]->np];
gc_sizf[dep]-=size2[nel[dep]->np];
gc_mxsz[dep]=max(gc_mxsz[dep],size2[nel[dep]->np]);
}
gc_mxsz[dep]=max(gc_mxsz[dep],gc_sizf[dep]);
if (gc_mxsz[dep]<vcore)
{
vcore=gc_mxsz[dep];
bcore=gc_now[dep];
}
}
pair<qword,qword> dfs2_ret[MAXN],dfs2_tt[MAXN];
int dfs2_now[MAXN],dfs2_col[MAXN];
pair<qword,qword> dfs2(int dep=)
{
// pair<qword,qword> ret,tt;
dfs2_ret[dep]=make_pair(val[dfs2_now[dep]],);
for (nel[dep]=V[dfs2_now[dep]];nel[dep];nel[dep]=nel[dep]->next)
{
if (nel[dep]->np==dfs2_now[dep-] || nel[dep]->disable)continue;
dfs2_now[dep+]=nel[dep]->np;
dfs2_col[dep+]=nel[dep]->col;
dfs2_tt[dep]=dfs2(dep+);
dfs2_ret[dep].second+=dfs2_tt[dep].second*(nel[dep]->col!=dfs2_col[dep]);
dfs2_ret[dep].first+=(dfs2_tt[dep].first+dfs2_tt[dep].second*val[dfs2_now[dep]]) *(nel[dep]->col!=dfs2_col[dep]);
}
return dfs2_ret[dep];
}
qword solve(int root,int siz)
{
if (siz==)return ;
vcore=INF;
gc_now[]=root;
gc_col[]=INF;
gc_now[]=root;
get_core_sizt=siz;
get_core();
int core=bcore;
gc_now[]=core;
gc_now[]=core;
get_core();
qword ans=;
Edge *ne;
for (ne=V[core];ne;ne=ne->next)
{
if (ne->disable)continue;
ne->disable=core;
ne->neg->disable=core;
ne->val=size[ne->np];
}
for (ne=V[core];ne;ne=ne->next)
{
if (ne->disable!=core)continue;
ans+=solve(ne->np,size2[ne->np]);
}
for (ne=V[core];ne;ne=ne->next)
{
if (ne->disable!=core)continue;
dfs2_now[]=dfs2_now[]=ne->np;
dfs2_col[]=ne->col;
ne->val2=dfs2();
}
Edge *ne2;
int t=;
map<int,qword> mp;
pair<qword,qword> sum=make_pair(,);
for (ne=V[core];ne;ne=ne->next)
{
if (ne->disable!=core)continue;
sum.first+=ne->val2.first;
sum.second+=ne->val2.second;
mp[ne->col]+=ne->val2.second;
}
qword ans2=;
for (ne=V[core];ne;ne=ne->next)
{
if (ne->disable!=core)continue;
ans+=ne->val2.first*(sum.second-mp[ne->col]);//分居兩邊
ans2+=val[core]*ne->val2.second*(sum.second-mp[ne->col]);//分局兩邊,中心貢獻
}
ans+=ans2/;
for (ne=V[core];ne;ne=ne->next)
{
if (ne->disable!=core)continue;
t+=ne->val2.second;//中心出發條數
ans+=ne->val2.first;//中心出發,外點貢獻
}
ans+=val[core]*t;
for (ne=V[core];ne;ne=ne->next)
{
if (ne->disable==core)
ne->disable=ne->neg->disable=;
}
return ans;
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
freopen(PROB".in","r",stdin);
freopen(PROB".out","w",stdout);
int i,j,k;
int x,y,z;
//scanf("%d",&n);
n=nextInt();
for (i=;i<=n;i++)
val[i]=nextInt();//scanf("%d",&val[i]);
for (i=;i<n;i++)
{
//scanf("%d%d%d",&x,&y,&z);
x=nextInt();
y=nextInt();
z=nextInt();
addedge(x,y,z);
}
// fa[1]=1;
// dfs1(1,0);
// init_lca();
qword ans=solve(,n);
printf(LL "\n",ans);
return ; }
Contest 高数题 樹的點分治 樹形DP的更多相关文章
- 【GDKOI2017】 两个胖子萌萌哒 小学奥数题
题目大意:给你一个$n\times m$的网格,你要在这个网格上画三角形. 三角形的顶点只能在网格的整点上,且至少有一条边平行于$x$或$y$轴,且三角形面积为整数.问你能画多少个不同的三角形. 两个 ...
- 又是一年NOIP然鹅我考的是高数(虽然我没打并且内容与NOIP无关)(手动滑稽)
好长时间没有写过总结了.也是高三结束,自招结束.成功的由国宝变为四害,整个人也是完全放松的,或者说是放肆的. 整个暑假都是游戏睡觉,游戏睡觉,也没有干什么有意义的事.有人说别人都在学习大一课程的时候我 ...
- BZOJ_2683_简单题&&BZOJ_1176_[Balkan2007]Mokia_CDQ分治+树状数组
BZOJ_2683_简单题&&BZOJ_1176_[Balkan2007]Mokia_CDQ分治+树状数组 Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加 ...
- 高数解题神器:拍照上传就出答案,这个中国学霸做的AI厉害了 | Demo
一位叫Roger的中国学霸小哥的拍照做题程序mathAI一下子火了,这个AI,堪称数学解题神器. 输入一张包含手写数学题的图片,AI就能识别出输入的数学公式,然后给出计算结果. 不仅加减乘除基本运算, ...
- 期权定价公式:BS公式推导——从高数和概率论角度
嗯,自己看了下书.做了点笔记,做了一些相关的基础知识的补充,尽力做到了详细,这样子,应该上过本科的孩子,只要有高数和概率论基础.都能看懂整个BS公式的推导和避开BS随机微分方程求解的方式的证明了.
- 《孙子算经》之"物不知数"题:中国剩余定理
1.<孙子算经>之"物不知数"题 今有物不知其数,三三数之剩二,五五数之剩七,七七数之剩二,问物几何? 2.中国剩余定理 定义: 设 a,b,m 都是整数. 如果 m ...
- 【xsy1116】数学题 奥数题
真实奥数题 题目大意:给你正整数k$,r$.问你存在多少对$(x,y)$,满足$x<y$且$x^2+y^2=kz^2$,并将所有符合条件的数对输出. 数据范围:$r≤1e9$,$k={1,2,3 ...
- 【Luogu3676】小清新数据结构题(动态点分治)
[Luogu3676]小清新数据结构题(动态点分治) 题面 洛谷 题解 先扯远点,这题我第一次看的时候觉得是一个树链剖分+线段树维护. 做法大概是这样: 我们先以任意一个点为根,把当前点看成是一棵有根 ...
- python基础===一道小学奥数题的解法
今早在博客园和大家分享了一道昨晚微博中看到的小学奥数题,后来有朋友给出了答案.然后我尝试用python解答它. 原题是这样的: 数学题:好事好 + 要做好 = 要做好事,求 “好.事.做.要”的值分别 ...
随机推荐
- 如何调试PHP的Core之获取基本信息 --------风雪之隅 PHP7核心开发者
http://www.laruence.com/2011/06/23/2057.html https://github.com/laruence PHP开发组成员, Zend兼职顾问, PHP7核心开 ...
- FileZilla命令行实现文件上传以及CreateProcess实现静默调用
应用需求: 用户在选择渲染作业时面临两种情况:一是选择用户远程存储上的文件:二是选择本地文件系统中的文件进行渲染.由于渲染任务是在远程主机上进行的,实际进行渲染时源文件也是在ftp目录 ...
- hdu2049.java
hdu 2049 不容易系列之(4)——考新郎 (组合+错排) 国庆期间,省城HZ刚刚举行了一场盛大的集体婚礼,为了使婚礼进行的丰富一些,司仪临时想出了有一个有意思的节目,叫做"考新郎&qu ...
- RMQ问题与ST算法
RMQ(Range Minimum/Maximum Query)问题是求区间最值问题. 对于长度为 n 的数组 A,进行若干次查询,对于区间 [L,R] 返回数组A中下标在 [L,R] 中的最小(大) ...
- C#入门教程(二)–C#常用快捷键、变量、类型转换-打造C#学习教程
C#入门教程(一)–.Net平台技术介绍.C#语言及开发工具介绍-打造C#学习教程 上次教程主要介绍了.Net平台以及C#语言的相关介绍.以及经典程序案例,helloworld程序. 初来乍到,第一次 ...
- asp.net页面刷新等问题
windows.open 关闭当前页面刷新父页面实现() { 在子页面中 Page.ClientScript.RegisterStartupScript(this.GetType(), "a ...
- inner join跟where查询的区别
- WisDom.Net 框架设计(五) 权限设计
WisDom.Net --权限设计 1.需求分析 基本在所有的管理系统中都离不开权限管理.可以这么说,权限管理是管理系统的核心所在. 权限管理说白一些就是每个人能够做什么,不能够做什么.可以说 ...
- MSSQL生成整个数据库的SQL脚本的工具 scptxfr.exe
scptxfr.exe的路径要正确declare @cMd varchar(1000)set @cmd = 'master.dbo.xp_cmdshell ' + '''c:\"Micros ...
- SQL SERVER 高级编程 - 自定义函数 拾忆
每个人都很忙,但是花10分钟复习下,总结下基础东西还是很有益处的. 背景: 总结一句,使用简便,还能递归,是的SQL更简洁,相对比一大堆的关联语句,而且关联一大堆还不一定实现特定功能.而且共用部分可以 ...