SPOJ QTREE3 Query on a tree again! ——Link-Cut Tree

【题目分析】

    QTREE2,一看是倍增算法,太懒了,不写了。( ̄_, ̄ )

    QTREE3,树链剖分可以做,发现链上的问题LCT也很好做。

    要是子树问题貌似可以DFS序。

    然后就成LCT模板题了。

    考前背板模式开启了。

【代码】

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define maxn 100005

struct LCT{
	int ch[maxn][2],fa[maxn],sta[maxn],top,rev[maxn],mx[maxn],col[maxn];
	bool isroot(int x)
	{return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
	void update(int x)
	{
		if (~mx[ch[x][0]]) mx[x]=mx[ch[x][0]];
		else if (col[x]) mx[x]=x;
		else if (~mx[ch[x][1]]) mx[x]=mx[ch[x][1]];
		else mx[x]=-1;
	}
	void pushdown(int x)
	{
		if (rev[x])
		{
			rev[x]^=1;
			rev[ch[x][0]]^=1;
			rev[ch[x][1]]^=1;
			swap(ch[x][0],ch[x][1]);
		}
	}
	void rot(int x)
	{
		int y=fa[x],z=fa[y],l,r;
		if (ch[y][0]==x) l=0; else l=1;
		r=l^1;
		if (!isroot(y))
		{
			if (ch[z][0]==y) ch[z][0]=x;
			else ch[z][1]=x;
		}
		fa[x]=z; fa[y]=x; fa[ch[x][r]]=y;
		ch[y][l]=ch[x][r]; ch[x][r]=y;
		update(y);update(x);
	}
	void splay(int x)
	{
		top=0;sta[++top]=x;
		for (int i=x;!isroot(i);i=fa[i]) sta[++top]=fa[i];
		while (top) pushdown(sta[top--]);
		
		while (!isroot(x))
		{
			int y=fa[x],z=fa[y];
			if (!isroot(y))
			{
				if (ch[z][0]==y^ch[y][0]==z) rot(y);
				else rot(x);
			}
			rot(x);
		}
	}
	void access(int x)
	{for(int t=0;x;t=x,x=fa[x])splay(x),ch[x][1]=t,update(x);}
	void makeroot(int x)
	{access(x);splay(x);rev[x]^=1;}
	int find(int x)
	{access(x);splay(x);while(ch[x][0])x=ch[x][0];return x;}
	void link(int x,int y)
	{makeroot(x);fa[x]=y;}
	void cut(int x,int y)
	{makeroot(x);access(y);splay(y);if (ch[y][0]==x)fa[x]=0;}
	int query(int x,int y)
	{makeroot(x);access(y);splay(y);return mx[y];}
	void init()
	{memset(mx,-1,sizeof mx);}
	void modify(int x)
	{access(x);splay(x);col[x]^=1;update(x);}
}lct;

int n,q;

int main()
{
	freopen("in.txt","r",stdin);
	scanf("%d%d",&n,&q);
	lct.init();
	for (int i=1;i<n;++i)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		lct.link(x,y);
	}
	while (q--)
	{
		int op,v;
		scanf("%d%d",&op,&v);
		if (op==0) lct.modify(v);
		else printf("%d\n",lct.query(1,v));
	}
}

  

转载于:https://www.cnblogs.com/SfailSth/p/6361710.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值