zoukankan      html  css  js  c++  java
  • 【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;
    }
    
  • 相关阅读:
    JSON Web Token
    Centos 7下编译安装PHP7.2(与Nginx搭配的安装方式)
    Nginx配置详解
    Centos 7下编译安装Nginx
    PHP常用正则验证
    拼手气红包函数
    获取汉字首字母大写
    根据生日计算年龄
    ffmpeg获取视频封面图片
    对象脑图总结
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8064533.html
Copyright © 2011-2022 走看看