SP16580 QTREE7 - Query on a tree VII(LCT)

Q T r e e 6 QTree6 QTree6的思路类似。

同样是两棵树,同样是维护那些信息,但是这次变成了维护最值。

那么维护虚+实的 m x mx mx数组肯定是照常维护。
但是虚子树的应该怎么办呢?
考虑到涉及到撤销这个东西,所以需要 m u l t i s e t multiset multiset
(注意删除一个值的时候,要删除地址而不是那个值)

我们可以对于每个点都开一个 m u l t i s e t multiset multiset来处理虚子树信息。

剩下的都差不多类似。
修改的时候,修改 v a l val val,记得要在 l c t lct lct a c c e s s + s p l a y access+splay access+splay一下,保证能及时 u p d a t e update update

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define pb push_back
#define mk make_pair
#define ll long long
#define lson ch[x][0]
#define rson ch[x][1]

using namespace std;

inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

const int maxn = 4e5+1e2;
const int inf = 1e9+10;
const int maxm = 2*maxn;

int val[maxn];

struct lct{
    int ch[maxn][2];
    int mx[maxn];
    multiset<int> s[maxn];
    int fa[maxn];
    int st[maxn];
    bool notroot(int x)
    {
    	return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
    }
    int son(int x)
    {
    	if (ch[fa[x]][0]==x) return 0;
    	else return 1;
    }
    int getmax(int x)
    {
    	if (s[x].empty()) return -inf;
    	else return (*s[x].rbegin());
    }
    void update(int x)
    {
    	mx[x]=val[x];
    	//if (x==1) cout<<mx[x]<<" "<<val[x]<<" "<<val[1]<<endl;
    	if (ch[x][0]) mx[x]=max(mx[x],mx[ch[x][0]]);
    	if (ch[x][1]) mx[x]=max(mx[x],mx[ch[x][1]]);
    	mx[x]=max(mx[x],getmax(x));
    }
    void rotate(int x)
    {
    	int y = fa[x],z = fa[y];
    	int b = son(x),c = son(y);
    	if(notroot(y)) ch[z][c]=x;
    	fa[x]=z;
    	ch[y][b]=ch[x][!b];
    	fa[ch[x][!b]]=y;
    	ch[x][!b]=y;
    	fa[y]=x;
    	update(y);
    	update(x);
    }
    void splay(int x)
    {
       while(notroot(x))
       {
          int y = fa[x],z = fa[y];
          int b = son(x),c = son(y);
          if (notroot(y))
          {
            if(b==c) rotate(y);
            else rotate(x);
          }
          rotate(x);
       }
       update(x);
    }
    void access(int x)
    {
    	for (int y=0;x;y=x,x=fa[x])
    	{
    		splay(x);
    		if (ch[x][1]) s[x].insert(mx[ch[x][1]]);
    		if (y) s[x].erase(s[x].find(mx[y]));
    		ch[x][1]=y;
    		update(x);
        }
    }
    void makeroot(int x)
    {
    	access(x);
    	splay(x);
    }
    int findroot(int x)
    {
       access(x);
       splay(x);
       while (ch[x][0]) x=ch[x][0];
       return x;
    }
    void split(int x,int y)
    {
    	makeroot(x);
    	access(y);
    	splay(y);
    }
    void link(int x,int y)
    {
    	split(x,y);
    	fa[x]=y;
    	s[y].insert(mx[x]);
    	update(y);
    }
    void cut(int x)
    {
    	access(x);
    	splay(x);
    	fa[ch[x][0]]=0;
    	ch[x][0]=0;
    }
};

lct b,w;
int n,m;
int point[maxn],nxt[maxm],to[maxm];
int cnt;
int fa[maxn];

void addedge(int x,int y)
{
    nxt[++cnt]=point[x];
    to[cnt]=y;
    point[x]=cnt;
}

void dfs(int x,int faa)
{
    fa[x]=faa;
    for (int i=point[x];i;i=nxt[i])
    {
        int p = to[i];
        if (p==faa) continue;
        dfs(p,x);
    }
}

int col[maxn];

int main()
{
  n=read();
  for (int i=1;i<n;i++) 
  {
  	 int x=read(),y=read();
  	 addedge(x,y);
  	 addedge(y,x);
  }
  dfs(1,n+1);
  for (int i=1;i<=n;i++) col[i]=read();
  for (int i=1;i<=n;i++) val[i]=read();
  for (int i=1;i<=n;i++) b.mx[i]=w.mx[i]=val[i];
  //cout<<val[1]<<endl;
  val[n+1]=-inf;
  w.mx[n+1]=b.mx[n+1]=val[n+1];
  for (int i=1;i<=n;i++) 
    if (col[i]) 
      b.link(i,fa[i]);
    else
      w.link(i,fa[i]);
  m=read();
  //cout<<1<<endl;
  for (int i=1;i<=m;i++)
  {
  	 int opt=read();
  	 if (opt==0)
  	 {
  	 	int x=read();
  	 	if (col[x])
  	 	{
  	 	  int roo = b.findroot(x);
  	 	  b.access(x);
  	 	  b.splay(roo);
  	 	  cout<<b.mx[b.ch[roo][1]]<<"\n";
  	    }
  	    else
  	    {
  	 	  int roo = w.findroot(x);
  	 	  w.access(x);
  	 	  w.splay(roo);//cout<<roo<<" "<<w.ch[roo][1]<<" "<<w.mx[w.ch[roo][1]]<<" "<<val[w.ch[roo][1]]<<"****"<<endl;
  	 	  cout<<w.mx[w.ch[roo][1]]<<"\n";
  	    }
     }
     if (opt==1)
     {
     	int x=read();
     	if (col[x])
     	{
     		b.cut(x);
     		col[x]=0;
     		w.link(x,fa[x]);
        }
        else
        {
        	col[x]=1;
        	w.cut(x);
        	b.link(x,fa[x]);
        }
     }
     if (opt==2)
     {
     	int x=read(),y=read();
     	//val[x]=y;
     	if (col[x])
     	{
     		b.access(x);
     		b.splay(x);
     		val[x]=y;
        }
        else
        {
        	w.access(x);
        	w.splay(x);
        	val[x]=y;
        }
     }
   }
  return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值