zoukankan      html  css  js  c++  java
  • 【bzoj4817】[Sdoi2017]树点涂色 LCT+LCA+线段树

    题目描述

    给出一棵n个点,以1为根的有根树,每个点初始染有互不相同的颜色。定义一条路径的权值为路径上的颜色种类数。现有m次操作,每次操作为以下三种之一:
    1 x: 把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
    2 x y: 求x到y的路径的权值。
    3 x y: 在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。

    输入

    第一行两个数n,m。
    接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
    接下来m行,表示操作,格式见题目描述
    1<=n,m<=100000

    输出

    每当出现2,3操作,输出一行。
    如果是2操作,输出一个数表示路径的权值
    如果是3操作,输出一个数表示权值的最大值

    样例输入

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

    样例输出

    3
    4
    2
    2


    题解

    LCT+线段树

    这不是和 bzoj3779重组病毒 一样的吗。。。还没有换根操作。。。

    使用线段树维护DFS序中区间最大值,然后按照那道题的思路使用LCT即可解决1、3操作。

    对于2操作,由$x$到根、$y$到根与$lca(x,y)$到根得到。具体答案为$f[x]+f[y]-2*f[lca]+1$。相当于$i$到根中有$f[i]-1$个颜色分界边,于是$x$到$y$中的颜色分界边数目即为$(f[x]-1)+(f[y]-1)-2*(f[lca]-1)$。所以颜色段数目为分界边数目+1=$f[x]+f[y]-2*f[lca]+1$。

    时间复杂度$O(nlog^2 n)$

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 100010
    #define lson l , mid , x << 1
    #define rson mid + 1 , r , x << 1 | 1
    using namespace std;
    int n , head[N] , to[N << 1] , next[N << 1] , cnt , pre[N][20] , deep[N] , log[N] , pos[N] , last[N] , tot , mx[N << 2] , tag[N << 2] , fa[N] , c[2][N];
    inline void add(int x , int y)
    {
    	to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
    }
    inline void pushup(int x)
    {
    	mx[x] = max(mx[x << 1] , mx[x << 1 | 1]);
    }
    void pushdown(int x)
    {
    	if(tag[x])
    	{
    		mx[x << 1] += tag[x] , mx[x << 1 | 1] += tag[x];
    		tag[x << 1] += tag[x] , tag[x << 1 | 1] += tag[x];
    		tag[x] = 0;
    	}
    }
    void update(int b , int e , int a , int l , int r , int x)
    {
    	if(b <= l && r <= e)
    	{
    		mx[x] += a , tag[x] += a;
    		return;
    	}
    	pushdown(x);
    	int mid = (l + r) >> 1;
    	if(b <= mid) update(b , e , a , lson);
    	if(e > mid) update(b , e , a , rson);
    	pushup(x);
    }
    int query(int b , int e , int l , int r , int x)
    {
    	if(b <= l && r <= e) return mx[x];
    	pushdown(x);
    	int mid = (l + r) >> 1 , ans = 0;
    	if(b <= mid) ans = max(ans , query(b , e , lson));
    	if(e > mid) ans = max(ans , query(b , e , rson));
    	return ans;
    }
    void dfs(int x)
    {
    	int i;
    	pos[x] = ++tot;
    	for(i = 1 ; (1 << i) <= deep[x] ; i ++ ) pre[x][i] = pre[pre[x][i - 1]][i - 1];
    	for(i = head[x] ; i ; i = next[i])
    		if(to[i] != pre[x][0])
    			pre[to[i]][0] = fa[to[i]] = x , deep[to[i]] = deep[x] + 1 , dfs(to[i]);
    	last[x] = tot , update(pos[x] , last[x] , 1 , 1 , n , 1);
    }
    inline int lca(int x , int y)
    {
    	int i;
    	if(deep[x] < deep[y]) swap(x , y);
    	for(i = log[deep[x] - deep[y]] ; ~i ; i -- )
    		if(deep[x] - deep[y] >= (1 << i))
    			x = pre[x][i];
    	if(x == y) return x;
    	for(i = log[deep[x]] ; ~i ; i -- )
    		if(deep[x] >= (1 << i) && pre[x][i] != pre[y][i])
    			x = pre[x][i] , y = pre[y][i];
    	return pre[x][0];
    }
    inline bool isroot(int x)
    {
    	return x != c[0][fa[x]] && x != c[1][fa[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;
    }
    inline void splay(int x)
    {
    	int y , z;
    	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 modify(int x , int a)
    {
    	if(!x) return;
    	while(c[0][x]) x = c[0][x];
    	update(pos[x] , last[x] , a , 1 , n , 1);
    }
    inline void access(int x)
    {
    	int t = 0;
    	while(x) splay(x) , modify(c[1][x] , 1) , c[1][x] = t , modify(t , -1) , t = x , x = fa[x];
    }
    int main()
    {
    	int m , i , opt , x , y , z;
    	scanf("%d%d" , &n , &m);
    	for(i = 2 ; i <= n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x) , log[i] = log[i >> 1] + 1;
    	dfs(1);
    	while(m -- )
    	{
    		scanf("%d%d" , &opt , &x);
    		if(opt == 1) access(x);
    		else if(opt == 2)
    		{
    			scanf("%d" , &y) , z = lca(x , y);
    			printf("%d
    " , query(pos[x] , pos[x] , 1 , n , 1) + query(pos[y] , pos[y] , 1 , n , 1) - 2 * query(pos[z] , pos[z] , 1 , n , 1) + 1);
    		}
    		else printf("%d
    " , query(pos[x] , last[x] , 1 , n , 1));
    	}
    	return 0;
    }
    

     

  • 相关阅读:
    ios UIWebView截获html并修改便签内容(转载)
    IOS获取系统时间 NSDate
    ios 把毫秒值转换成日期 NSDate
    iOS  如何判断当前网络连接状态  网络是否正常  网络是否可用
    IOS开发 xcode报错之has been modified since the precompiled header was built
    iOS系统下 的手机屏幕尺寸 分辨率 及系统版本 总结
    iOS 切图使用 分辨率 使用 相关总结
    整合最优雅SSM框架:SpringMVC + Spring + MyBatis 基础
    Java面试之PO,VO,TO,QO,BO
    Notes模板说明
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7659980.html
Copyright © 2011-2022 走看看