【bzoj4736/uoj#274】[清华集训2016]温暖会指引我们前行 语文题+LCT

题目描述

http://uoj.ac/problem/274


题解

语文题+LCT

对于这种语文题建议还是自己读题好一些。。。

读懂题后发现:由于温度互不相同,最大生成树上的路径必须走(不走的话温度大的边少了,字典序一定会更小),并且不能多走边(因为多走的话串会变长,长度大反而亏),因此答案就是最大生成树上的路径。

因此使用LCT维护最大生成树即可。维护两点之间权值最小的边。加边时如果已经连通,则判断加的边与最小的边那个大,如果新加的边大则删掉原来最小的边,加入新边。

至于边长度的处理,可以新建一个虚点代表这条边,点权位相应边长度。加边时连接虚点和x、虚点和y即可。

时间复杂度 $O(LCT·nlog n)$ 

#include <cstdio>
#include <algorithm>
#define N 400010
using namespace std;
typedef pair<int , int> pr;
int f[N] , v[N] , w[N] , fa[N] , c[2][N] , si[N] , sum[N] , rev[N] , px[N] , py[N];
pr mn[N];
char str[10];
int find(int x)
{
	return x == f[x] ? x : f[x] = find(f[x]);
}
inline void pushup(int x)
{
	si[x] = si[c[0][x]] + si[c[1][x]] + 1;
	mn[x] = min(pr(v[x] , x) , min(mn[c[0][x]] , mn[c[1][x]]));
	sum[x] = sum[c[0][x]] + sum[c[1][x]] + w[x];
}
inline void pushdown(int x)
{
	if(rev[x])
	{
		swap(c[0][c[0][x]] , c[1][c[0][x]]);
		swap(c[0][c[1][x]] , c[1][c[1][x]]);
		rev[c[0][x]] ^= 1 , rev[c[1][x]] ^= 1;
		rev[x] = 0;
	}
}
inline bool isroot(int x)
{
	return c[0][fa[x]] != x && c[1][fa[x]] != x;
}
void update(int x)
{
	if(!isroot(x)) update(fa[x]);
	pushdown(x);
}
inline void rotate(int x)
{
	int y = fa[x] , z = fa[y] , l = (c[1][y] == x) , r = l ^ 1;
	if(!isroot(y)) c[c[1][z] == y][z] = x;
	fa[x] = z , fa[y] = x , fa[c[r][x]] = y , c[l][y] = c[r][x] , c[r][x] = y;
	pushup(y) , pushup(x);
}
inline void splay(int x)
{
	int y , z;
	update(x);
	while(!isroot(x))
	{
		y = fa[x] , z = fa[y];
		if(!isroot(y))
		{
			if((c[0][y] == x) ^ (c[0][z] == y)) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
}
inline void access(int x)
{
	int t = 0;
	while(x) splay(x) , c[1][x] = t , pushup(x) , t = x , x = fa[x];
}
inline void makeroot(int x)
{
	access(x) , splay(x) , swap(c[0][x] , c[1][x]) , rev[x] ^= 1;
}
inline void link(int x , int y)
{
	makeroot(x) , fa[x] = y;
}
inline void split(int x , int y)
{
	makeroot(x) , access(y) , splay(y);
}
inline void cut(int x , int y)
{
	split(x , y) , fa[x] = c[0][y] = 0 , pushup(y);
}
int main()
{
	int n , m , i , id , x , y , z , t , l;
	scanf("%d%d" , &n , &m);
	mn[0] = pr(1 << 30 , 0);
	for(i = 1 ; i <= n ; i ++ ) f[i] = i , mn[i] = pr(v[i] = 1 << 30 , i) , sum[i] = w[i] = 0 , si[i] = 1;
	while(m -- )
	{
		scanf("%s" , str);
		if(str[0] == 'f')
		{
			scanf("%d%d%d%d%d" , &id , &x , &y , &t , &l) , x ++ , y ++ , id ++ ;;
			px[id] = x , py[id] = y , mn[id + n] = pr(v[id + n] = t , id + n) , sum[id + n] = w[id + n] = l , si[id + n] = 1;
			if(find(x) != find(y)) link(id + n , x) , link(id + n , y) , f[f[x]] = f[y];
			else
			{
				split(x , y);
				if(mn[y].first < t) z = mn[y].second - n , cut(z + n , px[z]) , cut(z + n , py[z]) , link(id + n , x) , link(id + n , y);
			}
		}
		else if(str[0] == 'm')
		{
			scanf("%d%d" , &x , &y) , x ++ , y ++ ;
			if(find(x) != find(y)) puts("-1");
			else split(x , y) , printf("%d
" , sum[y]);
		}
		else scanf("%d%d" , &id , &l) , splay(++id + n) , w[id + n] = l , pushup(id + n);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/GXZlegend/p/8064533.html