大力水手问禅师:“大师,很多事情都需要用很大力气才能完成,而我在吃了菠菜之后力气很大,于是就导致我现在非常依赖菠菜。我很讨厌我的现状,有没有办法少吃点菠菜甚至不吃菠菜却仍很有力气?”

禅师浅笑,答:“方法很简单,不过若想我教你,你需先下山徒手修路。”

山下是 n 座村庄从 1 到 n 编号,之间没有路相连。禅师给了大力水手一张草图,这张草图里 n 座村庄被 n−1 条双向道路连接,任意一个村庄都可以通过双向道路到达其它所有村庄。

现在大力水手要根据禅师的意思在村庄间修路。禅师规定大力水手需要在 m 天内完成任务,其中大力水手的修路方式如下:

  1. 第 i 天,禅师指定了两个村庄 vi 和 ui,在草图上 vi 号村庄到 ui 号村庄的最短路径上的所有村庄(包括 vi 和 ui)中,大力水手需要选出若干对村庄(一个村庄可以被重复选多次,当然大力水手在这天也可以一对村庄都不选),然后在选出的每一对村庄间修建双向道路。
  2. 在实地考察中大力水手发现,有 p 个限制关系 (ti,ai,bi),表示在第 ti 天无法在 ai 号村庄到 bi 号村庄间修路(路是双向的,所以自然也无法在 bi 号村庄到 ai 号村庄间修路)。
  3. 每一天都有个修理所需力气值 wi,表示在第 i 天每修建一条道路都要耗费 wi 点力气值。

大力水手开始蛮力干了起来,一罐又一罐地吞食菠菜,结果经常修建一些无用的道路,每天都累得筋疲力尽。

作为一个旁观者,请你帮大力水手求出要想让 m 天后任意一对村庄之间都可以互相到达,所需要的总力气值最少是多少。注意最后修出来的道路不必和草图一致。

输入格式

第一行三个非负整数 n,m,p。保证 n≥1。

接下来一行 n−1 个整数,其中第 i 个整数 fi+1 (1≤fi+1≤i)表示草图中 i+1 号村庄与 fi+1 号村庄间有一条双向道路。

接下来 m 行,第 i 行包含三个整数 vi,ui,wi (1≤vi,ui≤n,vi≠ui,1≤wi≤109)表示第 i 天禅师指定了 vi 号村庄和 ui 号村庄,大力水手修一条路耗费 wi 点力气值。

接下来 p 行,每行包含三个整数 ti,ai,bi 表示一个限制关系。保证 1≤ti≤m,1≤ai,bi≤n,ai≠bi,且草图上 ai 号村庄和 bi 号村庄都在 vti 号村庄到 uti 号村庄的最短路径上。另外,保证输入中不会出现重复的限制关系,即不会有两个限制关系 i,j 满足 ti=tj,ai=aj,bi=bj 或 ti=tj,ai=bj,bi=aj。

输出格式

输出一行一个整数,表示所需要的最小总力气值。保证至少存在一种修路的方法使得任意一对村庄之间都可以互相到达。

C/C++ 输入输出 long long 时请用 %lld。C++ 可以直接使用 cin/cout 输入输出。

样例一

input

5 2 3
1 1 3 3
2 4 1
5 4 2
1 3 2
1 3 1
1 3 4

output

6

explanation

第一天大力水手本来可以在 (1,2),(1,3),(1,4),(2,3),(2,4),(3,4) 间修路,但是由于第一天不能在 (3,2),(3,1) 和 (3,4) 间修路,所以可能的选择只有 (1,2),(1,4),(2,4)。对于第二天,大力水手可能的选择有 (3,4),(3,5),(4,5)。

一种可能的最优方案是,第一天大力水手在 (1,2),(1,4) 间修路,第二天在 (3,4),(4,5) 间修路,总共耗费 1+1+2+2=6 点力气值。

样例二

见样例数据下载。这个样例中 fi+1=i。

样例三

见样例数据下载。

限制与约定

测试点编号 n m p 其他
1 n≤100 m≤100 p≤100
2 n≤300000 m≤300000 p=0
3
4
5 n≤300000 m≤300000 p≤300000 保证对于 1<i≤n, fi+1=i
6
7 n≤300000 m≤300000 p≤300000
8
9
10

时间限制:1s

空间限制:256MB

后记

由于你的帮助,大力水手顺利修完了道路而且使用的力气值是原定计划的 0.01%。

大力水手对禅师说:“我明白了!我以前都是在使用蛮力,从今往后我要多思索,多使用巧力解决问题。”

禅师摆摆手,嘿嘿一笑:“对不起,我只是想请你帮忙修路而已。”

大力水手吃了一罐菠菜,把禅师打死了。

跪zsy,我终于知道怎样更有力气了.

考虑离线处理,先将所有天按w从小到大排序。设k为第i天的所有限制数,设u表示排序后第i天的u,v同理。

1、若dist(u,v)>k : 所有(u,v)的路径上的节点全部能连通。

2、若dist(u,v)<=k:这样总共的路径上点数=sigma(dist(u,v))<=p,我们只需想出一个只与路径上点数相关的算法。

对于1的情况,可以从下向上连边,用findset(tree,x)表示x向上第一个不与x连通的节点,findset(st,x)表示所有与x连通的节点,最多连n-1条边,故暴力连即可。

对于2的情况,我们把(u,v)的路径上的节点扔到一起并重新编号,考虑从每个点暴力向第一个不等于它的没有走过的点,判断是否有边(即是否有边的限制),用findset(path,x)表示大于x的第一个没有被访问过的点。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#define rep(s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
const int maxn=;
int n,m,p,First[maxn],Next[maxn],to[maxn],e,dep[maxn],fa[maxn],anc[maxn][],cnt;
void AddEdge(int u,int v) {
to[++e]=v;Next[e]=First[u];First[u]=e;
}
int first[maxn],next[maxn],u1[maxn],v1[maxn];
void dfs(int x) {
anc[x][]=fa[x];dep[x]=dep[fa[x]]+;
rep(,) anc[x][i]=anc[anc[x][i-]][i-];
for(int i=First[x];i;i=Next[i]) dfs(to[i]);
}
int LCA(int x,int y) {
if(dep[x]<dep[y]) swap(x,y);
for(int i=;i>=;i--) if(dep[x]-dep[y]>=<<i) x=anc[x][i];
for(int i=;i>=;i--) if(anc[x][i]!=anc[y][i]) x=anc[x][i],y=anc[y][i];
return x==y?x:fa[x];
}
int lim[maxn],st[maxn],tree[maxn],path[maxn];
void Addop(int day,int u,int v) {
lim[day]++;
u1[++cnt]=u;v1[cnt]=v;next[cnt]=first[day];first[day]=cnt;
}
struct Pair {
int x,y;
bool operator < (const Pair& ths) const {
if(x!=ths.x) return x<ths.x;
return y<ths.y;
}
}B[maxn*];
int ToT,len;
struct Day {
int u,v,w,id;
bool operator < (const Day& ths) const {return w<ths.w;}
}A[maxn];
long long ans;
int findset(int* pa,int x) {return pa[x]<?x:pa[x]=findset(pa,pa[x]);}
int merge(int u,int v,int w) {
if((u=findset(st,u))!=(v=findset(st,v))) ans+=w,st[u]=v;
}
int list[maxn],id[maxn],T[maxn],L[maxn],R[maxn];
void dfs(int u,int v,int w) {
if(u!=v) merge(list[u],list[v],w);
path[findset(path,u)]=u+;
for(int i=findset(path,);i<=len;i=findset(path,i+)) {
int p=lower_bound(T+L[u],T+R[u]+,i)-T;
if(T[p]!=i) dfs(i,v,w);
}
}
int main() {
n=read();m=read();p=read();
rep(,n) AddEdge(fa[i]=read(),i);
dfs();rep(,n) st[i]=tree[i]=-;
rep(,m) A[A[i].id=i].u=read(),A[i].v=read(),A[i].w=read();
sort(A+,A+m+);
rep(,p) {
int day=read();
Addop(day,read(),read());
}
rep(,m) {
int u=A[i].u,v=A[i].v,w=A[i].w,day=A[i].id;
int lca=LCA(u,v);len=dep[u]+dep[v]-dep[lca]*;
if(len>lim[day]) {
while(dep[u=findset(tree,u)]>dep[lca]) merge(u,tree[u]=fa[u],w);
while(dep[v=findset(tree,v)]>dep[lca]) merge(v,tree[v]=fa[v],w);
}
else {
int tot=;ToT=;
while(u!=lca) id[list[tot]=u]=tot++,u=fa[u];
while(v!=lca) id[list[tot]=v]=tot++,v=fa[v];
id[list[tot]=lca]=tot++;
for(int i=first[day];i;i=next[i]) {
int u2=id[u1[i]],v2=id[v1[i]];
B[++ToT]=(Pair){u2,v2};B[++ToT]=(Pair){v2,u2};
}
for(int i=;i<=len+;i++) path[i]=-;
sort(B+,B+ToT+);T[]=B[].y;L[B[].x]=;
for(int i=;i<=ToT+;i++) {
T[i]=B[i].y;
if(B[i].x!=B[i-].x) {
R[B[i-].x]=i-;
if(i!=ToT+) L[B[i].x]=i;
}
}
for(int i=;i<=len;i++) if(findset(path,i)==i) dfs(i,i,w);
}
}
printf("%lld\n",ans);
return ;
}

UOJ#61. 【UR #5】怎样更有力气的更多相关文章

  1. 【UOJ#61】【UR #5】怎样更有力气(最小生成树)

    [UOJ#61][UR #5]怎样更有力气(最小生成树) 题面 UOJ 题解 最最最暴力的想法是把所有边给处理出来然后跑\(MST\). 考虑边权的情况,显然离线考虑,把么一天按照\(w_i\)进行排 ...

  2. 「UR#5」怎样更有力气

    「UR#5」怎样更有力气 解题思路 考虑没有限制的情况,一定是把操作离线下来,按照边权从小到达做.可以发现,如果没有限制,完全图是多余的,直接拿树边进行合并就可以了.我们要做这么一件事情,把每个点属于 ...

  3. YYHS-怎样更有力气

    题目描述 OI大师抖儿在夺得银牌之后,顺利保送pku.这一天,抖儿问长者:"我虽然已经保送了,但我的志向是为国家健康工作五十年.请问我应该怎样变得更有力气?"  长者回答:&quo ...

  4. 【NOIP2017练习】怎样更有力气(二分答案,线性扫描)

    题意:OI大师抖儿在夺得银牌之后,顺利保送pku.这一天,抖儿问长者:“我虽然已经保送了,但我的志向是为国家健康工作五十年.请问我应该怎样变得更有力气?”   长者回答:“你啊,Too Young T ...

  5. UOJ 【UR #5】怎样跑得更快

    [UOJ#62]怎样跑得更快 题面 这个题让人有高斯消元的冲动,但肯定是不行的. 这个题算是莫比乌斯反演的一个非常巧妙的应用(不看题解不会做). 套路1: 因为\(b(i)\)能表达成一系列\(x(i ...

  6. 【UR #5】怎样更有力气

    Problem Description 大力水手问禅师:"大师,很多事情都需要用很大力气才能完成,而我在吃了菠菜之后力气很大,于是就导致我现在非常依赖菠菜.我很讨厌我的现状,有没有办法少吃点 ...

  7. UOJ61. 【UR #5】怎样更有力气

    题目链接 Statement 给定一棵 \(n\) 点树 \(T\) 和 \(m\) 个操作 v u w : 在 \(T\) 中 \(u,v\) 的最短路上所有点里面选出若干对(可以不选,可以重复), ...

  8. UOJ #22 UR #1 外星人

    LINK:#22. UR #1 外星人 给出n个正整数数 一个初值x x要逐个对这些数字取模 问怎样排列使得最终结果最大 使结果最大的方案数又多少种? n<=1000,x<=5000. 考 ...

  9. UOJ.52.[UR #4]元旦激光炮(交互 思路)

    题目链接 \(Description\) 交互库中有三个排好序的,长度分别为\(n_a,n_b,n_c\)的数组\(a,b,c\).你需要求出所有元素中第\(k\)小的数.你可以调用至多\(100\) ...

随机推荐

  1. Html form 表单提交前验证

    可以使用form表单的onsubmit方法,在提交表单之前,对表单或者网页中的数据进行检验. onsubmit指定的方法返回true,则提交数据:返回false不提交数据. 直接看下面的代码: 1 & ...

  2. ubuntu搭建lamp环境

    首先安装软件: sudo apt-get install apache2 sudo apt-get install php5 sudo apt-get install mysql-server sud ...

  3. MySQL的LIMIT与分页优化

    在系统中需要进行分页操作的时候,我们通常会使用LIMIT加上偏移量的办法实现,同时加上合适的ORDER BY子句.如果有对应的索引,通常效率会不错,否则,MySQL需要做大量的文件排序操作. 一个非常 ...

  4. [Android Pro] Android Support 包里究竟有什么

    reference to : http://www.2cto.com/kf/201411/350928.html 随着 Android 5.0 Lollipop 的发布,Android 又为我们提供了 ...

  5. Android之自定义ViewGroup

    概述 在写代码之前,我必须得问几个问题: 1.ViewGroup的职责是啥? ViewGroup相当于一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属性, ...

  6. java equals 和 "==" 比较

    java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型.byte,short,char,int,long,float,double,boolean   他们之间的比较,应用双等号(== ...

  7. 一、HTML和CSS基础--HTML+CSS基础课程--第4部分

    第七章 CSS的继承.层叠和特殊性 继承:CSS的某些样式是具有继承性的,那么什么是继承呢?继承是一种规则,它允许样式不仅应用于某个特定html标签元素,而且应用于其后代. 特殊性
权值的规则: 标签 ...

  8. 使用ASP.NET Web API自带的类库实现对CORS的支持(在开发中使用这种方式)(转载)

    在<通过扩展让ASP.NET Web API支持W3C的CORS规范>中我们通过自定义的HttpMessageHandler为ASP.NET Web API赋予了跨域资源共享的能力,具体来 ...

  9. jQuery 重新温习 遗忘知识点

    解决jQuery和其他库的冲突 当把jQuery和其他JavaScript库(例如Prototype.MooTools或YUI)一起使用时 <script> jQuery.noConfli ...

  10. 如何将消息发送给Whatsapp联系人

    如何将消息发送给Whatsapp联系人 (由于本人喜欢word文档编辑,不喜欢网络编辑,所以仍然提供pdf版文档,方便查阅http://files.cnblogs.com/franksunny/sen ...