这个题还是挺有意思的...

一个小结论是:在一个$n$点$m$边的图中,如果度数最小的点度数为$d$,那么$d^2=O(m)$,因为$d\leq\frac{2m}n$,所以$d^2\leq dn\leq2m$

把链按权值从小到大排序,对一条链$(u,v)$,设在它上面的限制数量为$k$,如果$k\lt\text{dis}(u,v)$,那么我们可以让这条链上的所有点连通,直接用并查集把链上的点暴力合并即可

否则我们想要在$O(k)$的时间内计算答案,这样这部分的总复杂度就是$O(p)$的

先把限制建成图,找到度数最小的那个点$x$,不与$x$相邻的那些点(设此集合再加上$x$为$X$)都可以和它合并,现在考虑那些与$x$相邻的点(设此集合为$Y$),只有两种可能的连边:$X\rightarrow Y$,$Y\rightarrow Y$

对于$X\rightarrow Y$,我们枚举$y\in Y$,如果$d_y\lt\left\lvert X\right\rvert$,那么它一定可以和$X$中某点连边,否则$O(d_y)$打标记再遍历所有$X$中节点即可,这部分复杂度是$O\left(\sum d_y\right)=O(k)$

对于$Y\rightarrow Y$,直接$O\left(d_x^2\right)$枚举即可,由开始的那个结论得这部分的复杂度也是$O(k)$

最后一个小问题是:要维护一个支持链并和两点并的并查集,这里维护两个并查集:链并的和实际集合的,在链并操作的同时更新实际集合的并查集即可

总复杂度$O(n+m\log m+q\alpha(n))$,跑得非常快

#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int inf=2147483647;
int fa[300010],dep[300010],d[300010],f[300010],ot[300010],N,M;
bool vis[300010];
ll ans;
struct ch{
	int x,y,w,i;
}p[300010];
bool operator<(ch a,ch b){return a.w<b.w;}
struct edge{
	int x,y;
	edge(int x=0,int y=0):x(x),y(y){}
};
vector<edge>e[300010];
vector<edge>::iterator it;
vector<int>g[300010];
vector<int>::iterator i1,i2;
struct dsu{
	int fa[300010];
	int get(int x){return x==fa[x]?x:(fa[x]=get(fa[x]));}
}c,b;
void merge(int x,int y,int w){
	x=b.get(x);
	y=b.get(y);
	if(x!=y){
		ans+=w;
		b.fa[x]=y;
	}
}
bool check(int x,int y,int k){
	while(k--){
		if(dep[x]<dep[y])swap(x,y);
		x=fa[x];
		if(x==y)return 0;
	}
	return 1;
}
void get(int x,int y){
	N=0;
	while(x!=y){
		if(dep[x]<dep[y])swap(x,y);
		f[++N]=x;
		x=fa[x];
	}
	f[++N]=x;
}
int main(){
	int n,m,q,i,j,x,y,mn;
	scanf("%d%d%d",&n,&m,&q);
	for(i=2;i<=n;i++)scanf("%d",fa+i);
	for(i=1;i<=n;i++)dep[i]=dep[fa[i]]+1;
	for(i=1;i<=m;i++){
		scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].w);
		p[i].i=i;
	}
	while(q--){
		scanf("%d%d%d",&i,&x,&y);
		e[i].push_back(edge(x,y));
	}
	sort(p+1,p+m+1);
	for(i=1;i<=n;i++)c.fa[i]=b.fa[i]=i;
	for(i=1;i<=m;i++){
		#define merge(x,y) merge(x,y,p[i].w)
		vector<edge>&v=e[p[i].i];
		if(check(p[i].x,p[i].y,v.size())){
			x=c.get(p[i].x);
			y=c.get(p[i].y);
			while(x!=y){
				if(dep[x]<dep[y])swap(x,y);
				merge(x,fa[x]);
				c.fa[x]=fa[x];
				x=c.get(x);
			}
		}else{
			for(it=v.begin();it!=v.end();it++){
				x=it->x;
				y=it->y;
				d[x]++;
				d[y]++;
				g[x].push_back(y);
				g[y].push_back(x);
			}
			get(p[i].x,p[i].y);
			x=0;
			mn=inf;
			for(j=1;j<=N;j++){
				if(d[f[j]]<mn){
					mn=d[f[j]];
					x=f[j];
				}
			}
			for(i1=g[x].begin();i1!=g[x].end();i1++)vis[*i1]=1;
			M=0;
			for(j=1;j<=N;j++){
				if(!vis[f[j]])ot[++M]=f[j];
			}
			for(j=1;j<=M;j++)merge(x,ot[j]);
			for(i1=g[x].begin();i1!=g[x].end();i1++)vis[*i1]=0;
			for(i1=g[x].begin();i1!=g[x].end();i1++){
				y=*i1;
				for(i2=g[y].begin();i2!=g[y].end();i2++)vis[*i2]=1;
				for(i2=g[x].begin();i2!=g[x].end();i2++){
					if(!vis[*i2])merge(y,*i2);
				}
				for(i2=g[y].begin();i2!=g[y].end();i2++)vis[*i2]=0;
				if((int)g[y].size()<M)
					merge(x,y);
				else{
					for(i2=g[y].begin();i2!=g[y].end();i2++)vis[*i2]=1;
					for(j=1;j<=M;j++){
						if(!vis[ot[j]])merge(ot[j],y);
					}
					for(i2=g[y].begin();i2!=g[y].end();i2++)vis[*i2]=0;
				}
			}
			for(it=v.begin();it!=v.end();it++){
				x=it->x;
				y=it->y;
				d[x]=d[y]=0;
				g[x].clear();
				g[y].clear();
			}
		}
	}
	printf("%lld",ans);
}

[UOJ61]怎样更有力气的更多相关文章

  1. UOJ#61. 【UR #5】怎样更有力气

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

  2. YYHS-怎样更有力气

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

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

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

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

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

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

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

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

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

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

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

  8. 校际联合Contest

    每次开一个坑都像是重新被碾压的预感 最近的新闻,以前很喜欢乔任梁的<复活>...然后他就死了...感觉我再多愁善感一点的话...就要悲伤逆流成河了吧... Contest 09/24(乐滋 ...

  9. 如何编写高质量的 jQuery 代码?

    想必大家对于jQuery这个最流行的javascript类库都不陌生,而且只要是前端开发人员肯定或多或少的使用或者接触过,在今天的这篇文章中,我们将介绍一些书写高质量jQuery代码的原则,我们不单单 ...

随机推荐

  1. Vue SPA 首屏加载优化实践

    写在前面 本文记录笔者在Vue SPA项目首屏加载优化过程中遇到的一些坑及优化方案! 我们以 vue-cli 工具为例,使用 vue-router 搭建SPA应用,UI框架选用 element-ui ...

  2. php常用函数——字符串函数

    php常用函数——字符串函数

  3. flask插件系列之flask_caching缓存

    前言 为了尽量减少缓存穿透,同时减少web的响应时间,我们可以针对那些需要一定时间才能获取结果的函数和那些不需要频繁更新的视图函数提供缓存服务,可以在一定的时间内直接返回结果而不是每次都需要计算或者从 ...

  4. python算法之近似熵、互近似熵算法

    理论基础 近似熵? 定义:近似熵是一个随机复杂度,反应序列相邻的m个点所连成折线段的模式的互相近似的概率与由m+1个点所连成的折线段的模式相互近似的概率之差. 作用:用来描述复杂系统的不规则性,越是不 ...

  5. python基础===100盏灯的问题

    闪存里有人这样提问这样: 第一轮操作所有电灯,第二轮操作第2盏,第4盏开关,以此类推,第三轮改变编号为3的倍数的电灯,第3盏,第6盏,如果原来那盏灯是亮的,就熄灭它,如果原来是灭的,就点亮它,以此类推 ...

  6. 大数据系列之kafka监控kafkaoffsetmonitor安装

    1.下载kafkaoffsetmonitor的jar包,可以到github搜索kafkaoffsetmonitor,第一个就是,里面可以下载编译好了的包. KafkaOffsetMonitor-ass ...

  7. 【51nod1006】simple KMP

    原题意看的挺迷糊的,后来看了http://blog.csdn.net/YxuanwKeith/article/details/52351335大爷的题意感觉清楚的多…… 做法也非常显然了,用树剖维护后 ...

  8. 【BubbleCup X】D. Exploration plan

    这个题首先一眼能看出二分答案…… 毕竟连可爱的边界都给你了. 下面就是怎么check 首先预处理跑一遍floyed,预处理出最短路. 用网络流判断能否达到即可. #include<bits/st ...

  9. 设计模式之笔记--代理模式(Proxy)

    代理模式(Proxy) 定义 代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问. 类图 描述 Subject,定义了ConcreteSubject和Proxy的共用接口,这样就可以 ...

  10. 未找到与约束 ContractName Microsoft.VisualStudio.Utilitues.IContentTypeRegistryService......

    1.问题提出 用VS 2013 with Update5 开发项目,点击项目中的文件,发现打不开,抛出如下的错误. 错误提示: 未找到与约束 ContractName Microsoft.Visual ...