zoukankan      html  css  js  c++  java
  • [SPOJ2939]Qtree5

    [SPOJ2939]Qtree5

    Tags:题解


    题意

    链接
    给你(n)个节点的黑白树,初始全黑。每次可以翻转某点颜色,或查询距离某点最近的白点的距离。(nle 10^5)。强制LCT,不准动点分。

    题解

    这题神了。
    LCT中每个splay的中序遍历是一条直上直下的链。

    维护什么呢?

    (splay)中的(x)点维护(x)(splay)子树中,在原树上深度最深和深度最浅的点、到达(x)(splay)子树中的点在原图上的子树中、最近的白点的距离。分别记为(lm、rm)

    怎么维护呢?

    需要维护原图信息那么开一个(set)维护虚子树
    深度最浅的点是x的最左儿子,它的最近白点距离可能由以下几方面

    • 左子树的答案
    • 左子树的(siz)(若(x)为白点)
    • 左子树的(siz+1+)右子树的答案

    同理维护最深的点。

    怎么查呢?

    (x)(Access)这样它就是这条链上最深的点了。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<set>
    #define lc t[x].ch[0]
    #define rc t[x].ch[1]
    using namespace std;
    const int N=2e5+10,inf=1e9;
    int n,q,head[N],cnt;
    struct edge{int next,to;}a[N];
    struct Node{int ch[2],siz,lm,rm,col,fa;multiset<int> s;}t[N];
    multiset<int>::iterator it;
    void link(int x,int y) {a[++cnt]=(edge){head[x],y};head[x]=cnt;}
    int isroot(int x) {return t[t[x].fa].ch[0]!=x&&t[t[x].fa].ch[1]!=x;}
    int fin(int x) {return t[x].s.empty()?inf:*t[x].s.begin();}
    void pushup(int x)
    {
    	t[x].siz=t[lc].siz+t[rc].siz+1;
    	t[x].lm=min(t[lc].lm,t[lc].siz+min(t[x].col?0:inf,min(fin(x),t[rc].lm+1)));
    	t[x].rm=min(t[rc].rm,t[rc].siz+min(t[x].col?0:inf,min(fin(x),t[lc].rm+1)));
    }
    void rotate(int x)
    {
    	int y=t[x].fa,z=t[y].fa;
    	int k=t[y].ch[1]==x;
    	if(!isroot(y)) t[z].ch[t[z].ch[1]==y]=x; t[x].fa=z;
    	t[y].ch[k]=t[x].ch[k^1];                 t[t[x].ch[k^1]].fa=y;
    	t[x].ch[k^1]=y;                          t[y].fa=x;
    	pushup(y);
    }
    void splay(int x)
    {
    	while(!isroot(x))
    	{
    		int y=t[x].fa,z=t[y].fa;
    		if(!isroot(y)) (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
    		rotate(x);
    	}
    	pushup(x);
    }
    void Access(int x)
    {
    	for(int y=0;x;y=x,x=t[x].fa)
    	{
    		splay(x);t[x].s.insert(t[rc].lm+1);
    		rc=y;it=t[x].s.lower_bound(t[rc].lm+1);
    		if(it!=t[x].s.end()&&*it==t[rc].lm+1) t[x].s.erase(it);
    		pushup(x);
    	}
    }
    void dfs(int x,int fr)
    {
    	for(int i=head[x];i;i=a[i].next)
    	{
    		int R=a[i].to;if(fr==R) continue;
    		t[R].fa=x;t[x].s.insert(inf+1);dfs(R,x);
    	}
    	pushup(x);
    }
    int main()
    {
    	cin>>n;
    	t[0].lm=t[0].rm=inf+1;
    	for(int i=1,x,y;i<n;i++)
    		scanf("%d%d",&x,&y),link(x,y),link(y,x);
    	cin>>q;dfs(1,0);
    	for(int i=1;i<=q;i++)
    	{
    		int op,x;scanf("%d%d",&op,&x);
    		if(op==0)
    		{
    			Access(x);splay(x);
    			t[x].col^=1;pushup(x);
    		}
    		else
    		{
    			Access(x);splay(x);
    			printf("%d
    ",t[x].rm>n?-1:t[x].rm);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    4.Android开发笔记:Activity的生命周期、启动方式、最佳实践
    3.Android开发笔记:Activity 数据传递
    2.Android开发笔记:Activity
    1.《Android开发笔记》系列
    JS
    Mongodb 学习笔记简介
    Sql Server MySql 日期
    实现tomcat与IIS共用80端口
    学习Microsoft SQL Server 2008技术内幕:T-SQL语法基础--第4章
    学习Microsoft SQL Server 2008技术内幕:T-SQL语法基础
  • 原文地址:https://www.cnblogs.com/xzyxzy/p/10347633.html
Copyright © 2011-2022 走看看