• 【CF1137F】Matches Are Not a Child's Play


    题目

    题目链接:https://codeforces.com/problemset/problem/1137/F
    我们定义一棵树的删除序列为:每一次将树中编号最小的叶子删掉,将该节点编号加入到当前序列的最末端,最后只剩下一个节点时将该节点的编号加入到结尾。
    现在给出一棵(n)个节点的树,有(m)次操作:
    up v:将(v)号节点的编号变为当前所有节点编号的(max + 1)
    when v:查询(v)在当前树的删除序列中是第几号元素
    compare u v:查询(u)(v)在当前树的删除序列中谁更靠前

    (n,mleq 2 imes 10^5)

    思路

    compare 操作直接求出两个点的排名然后比较一下就好了。
    我们发现这个删除序列有一个性质:把删除序列看作一个栈,我们从大到小枚举点 (x),每次找到 (x) 祖先中深度最深的已经被加入到序列中的点 (y),那么从 (y) 的儿子到 (x) 路径上的点会依次扔进栈中,最后栈中从栈顶到栈底就是删除序列。
    显然最大值是序列的最后一个元素。我们把最大值看作树根,考虑把 (x) 变为最大值之后的影响:把 (x) 看作根,设 (y) 是上一步骤的最大值,显然 (x)(y) 的节点全部会在最后被扔进栈中,然后其他节点的相对位置不变。
    这个很像 LCT makert 的过程。也就是我们每次把 (x)(y) 的路径用一个新的编号最大的颜色覆盖,然后对于一个点 (p) 的答案,就是颜色小于 (col_p) 的节点数量,再加上颜色等于 (col_p),且深度大于 (p) 的节点数量。
    那么直接用 LCT 维护就好了。用一个树状数组维护颜色数量的前缀和,询问的时候答案就在树状数组上求前缀和,再加上 Splay 的右子树节点数量。
    修改操作就直接把 (x) makert,注意 access 的过程中要修改树状数组。
    时间复杂度 (O(mlog^2 n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=200010;
    int n,m,t,tot,head[N],deg[N];
    char typ[10];
    
    struct edge
    {
    	int next,to;
    }e[N*2];
    
    void add(int from,int to)
    {
    	e[++tot]=(edge){head[from],to};
    	head[from]=tot;
    }
    
    struct BIT
    {
    	int c[N*2];
    	
    	void add(int x,int v)
    	{
    		if (!x) return;
    		for (int i=x;i<N*2;i+=i&-i)
    			c[i]+=v;
    	}
    	
    	int query(int x)
    	{
    		int ans=0;
    		for (int i=x;i;i-=i&-i)
    			ans+=c[i];
    		return ans;
    	}
    }bit;
    
    struct LCT
    {
    	int fa[N],ch[N][2],siz[N],col[N];
    	bool rev[N];
    	
    	bool pos(int x) { return x==ch[fa[x]][1]; }
    	bool notrt(int x) { return x==ch[fa[x]][0] || x==ch[fa[x]][1]; }
    	
    	void pushup(int x)
    	{
    		siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    	}
    	
    	void pushdown(int x)
    	{
    		if (rev[x])
    		{
    			int lc=ch[x][0],rc=ch[x][1];
    			if (lc) swap(ch[lc][0],ch[lc][1]),rev[lc]^=1;
    			if (rc) swap(ch[rc][0],ch[rc][1]),rev[rc]^=1;
    			rev[x]=0;
    		}
    		if (ch[x][0]) col[ch[x][0]]=col[x];
    		if (ch[x][1]) col[ch[x][1]]=col[x];
    	}
    	
    	void rotate(int x)
    	{
    		int y=fa[x],z=fa[y],k=pos(x),c=ch[x][k^1];
    		if (notrt(y)) ch[z][pos(y)]=x; ch[x][k^1]=y; ch[y][k]=c;
    		if (c) fa[c]=y; fa[y]=x; fa[x]=z;
    		pushup(y); pushup(x);
    	}
    	
    	void splay(int x)
    	{
    		stack<int> st; st.push(x);
    		for (int i=x;notrt(i);i=fa[i]) st.push(fa[i]);
    		for (;st.size();st.pop()) pushdown(st.top());
    		for (;notrt(x);rotate(x))
    			if (notrt(fa[x])) rotate(pos(x)==pos(fa[x])?fa[x]:x);
    	}
    	
    	void access(int x)
    	{
    		int y=0;
    		for (;x;y=x,x=fa[x])
    		{
    			splay(x);
    			bit.add(col[x],-siz[x]+siz[ch[x][1]]);
    			if (ch[x][1]) col[ch[x][1]]=col[x];
    			ch[x][1]=y;
    			pushup(x);
    		}
    		col[y]=t;
    		bit.add(t,siz[y]);
    	}
    	
    	void makert(int x)
    	{
    		t++;
    		access(x); splay(x);
    		swap(ch[x][0],ch[x][1]); rev[x]^=1;
    	}
    	
    	int query(int x)
    	{
    		splay(x);
    		return bit.query(col[x]-1)+siz[ch[x][1]]+1;
    	}
    }lct;
    
    void dfs(int x,int fa)
    {
    	lct.fa[x]=fa; lct.siz[x]=1;
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (v!=fa) dfs(v,x);
    	}
    }
    
    void topsort()
    {
    	priority_queue<int> q;
    	for (int i=1;i<=n;i++)
    		if (deg[i]==1) q.push(-i);
    	while (q.size())
    	{
    		int u=-q.top(); q.pop();
    		lct.makert(u);
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			int v=e[i].to;
    			if (deg[v]>1)
    			{
    				deg[v]--;
    				if (deg[v]==1) q.push(-v);
    			}
    		}
    	}
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&m);
    	for (int i=1,x,y;i<n;i++)
    	{
    		scanf("%d%d",&x,&y);
    		add(x,y); add(y,x); deg[x]++; deg[y]++;
    	}
    	dfs(1,0);
    	topsort();
    	while (m--)
    	{
    		scanf("%s",typ);
    		if (typ[0]=='u')
    		{
    			int x;
    			scanf("%d",&x);
    			lct.makert(x);
    		}
    		if (typ[0]=='w')
    		{
    			int x;
    			scanf("%d",&x);
    			printf("%d
    ",lct.query(x));
    		}
    		if (typ[0]=='c')
    		{
    			int x,y;
    			scanf("%d%d",&x,&y);
    			printf("%d
    ",lct.query(x)<lct.query(y)?x:y);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    python之函数一
    python之字典
    分支与master切换 | MyEclipse git怎么提交代码
    gitignore的使用详细图解
    1.1(学习笔记)Servlet简介及一个简单的实例
    10.4(java学习笔记)CLOB,BLOB基本操作
    10.3(Java学习笔记)JDBC时间操作
    10.2(java学习笔记)JDBC事务简述
    10.1(java学习笔记)JDBC基本操作(连接,执行SQL语句,获取结果集)
    9.1(java学习笔记)正则表达式
  • 原文地址:https://www.cnblogs.com/stoorz/p/14442553.html
Copyright © 2020-2023  润新知