zoukankan      html  css  js  c++  java
  • 【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;
    }
    
  • 相关阅读:
    Jmeter之http性能测试实战 非GUI模式压测 NON-GUI模式 结果解析TPS——干货(十一)
    UI Recorder 自动化测试 回归原理(九)
    UI Recorder 自动化测试 录制原理(八)
    UI Recorder 自动化测试 整体架构(七)
    UI Recorder 自动化测试 配置项(六)
    UI Recorder 自动化测试 工具栏使用(五)
    UI Recorder 自动化测试 回归测试(四)
    UI Recorder 自动化测试 录制(三)
    UI Recorder 自动化测试工具安装问题疑难杂症解决(二)
    UI Recorder 自动化测试安装教程(一)
  • 原文地址:https://www.cnblogs.com/stoorz/p/14442553.html
Copyright © 2011-2022 走看看