题解QTree3

Posted h-lka

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解QTree3相关的知识,希望对你有一定的参考价值。

题目描述

给出N个点的一棵树(N-1条边),节点有白有黑,初始全为白

有两种操作:

0 i : 改变某点的颜色(原来是黑的变白,原来是白的变黑)

1 v : 询问1到v的路径上的第一个黑点,若无,输出-1

输入输出格式

输入格式:

 

第一行 N,Q,表示N个点和Q个操作

第二行到第N行N-1条无向边

再之后Q行,每行一个操作"0 i" 或者"1 v" (1 ≤ i, v ≤ N).

 

输出格式:

 

对每个1 v操作输出结果

输入输出样例:

9 8
1 2
1 3
2 4
2 9
5 9
7 9
8 9
6 8
1 3
0 8
1 6
1 7
0 2
1 9
0 2
1 9 

输出:

-1
8
-1
2
-1

解:

题意要求我们单点修改颜色,查询距离。

这题当然不止LCT一种做法,也可以树剖。最近学了下LCT就练了一下QwQ.

我们先用一遍dfs求深度。求出深度后,LCT中维护除正常信息之外,维护点子树中黑点深度最浅的id编号以及点的col。

pushup:

inline void pushup(int x)
    if(tr[x].col)tr[x].id=x;
    else tr[x].id=0;
    if(dep[tr[tr[x].ch[0]].id]<dep[tr[x].id])tr[x].id=tr[tr[x].ch[0]].id;
    if(dep[tr[rc].id]<dep[tr[x].id])tr[x].id=tr[rc].id;

这个就不说了吧。

由于要dfs求深度,用前向星存边(树剖基本操作qwq),dfs即可。

(学树剖的话一定敲一下旅游那道题,基础操作比较全。)

记住,先dfs再Link!

每次单点修改,makeroot之后col^=1。

查询把v和1(伪根)split一下输出id即可。

代码:

 

#include<cstdio>
#define MAXN 500000
#include<iostream>
using namespace std;
#define lc tr[x].ch[0]
#define rc tr[x].ch[1]
struct node
    int ch[2],fa,rev,id,col;
tr[500000];
int n,m,dep[MAXN],head[MAXN];
int tot,a[MAXN],b[MAXN],opt,f;
struct EDGE
    int next,to;
e[MAXN];
inline bool root(int x)
    int g=tr[x].fa;
    return !(tr[g].ch[1]==x||tr[g].ch[0]==x);

inline void pushup(int x)
    if(tr[x].col)tr[x].id=x;
    else tr[x].id=0;
    if(dep[tr[tr[x].ch[0]].id]<dep[tr[x].id])tr[x].id=tr[tr[x].ch[0]].id;
    if(dep[tr[rc].id]<dep[tr[x].id])tr[x].id=tr[rc].id;
inline void pushr(int x)
    if(!x)return;
    swap(tr[x].ch[0],tr[x].ch[1]);
    tr[x].rev^=1;
inline void pushdown(int x)
    if(tr[x].rev)
        pushr(tr[x].ch[0]);
        pushr(tr[x].ch[1]);
        tr[x].rev=0;
    
inline void push(int x)
    if(!root(x))push(tr[x].fa);
    pushdown(x);
inline void rotate(int x)
    int y=tr[x].fa,z=tr[y].fa,k=tr[y].ch[1]==x;
    if(!root(y))tr[z].ch[tr[z].ch[1]==y]=x;
    tr[x].fa=z;tr[y].ch[k]=tr[x].ch[k^1];
    if(tr[x].ch[k^1])tr[tr[x].ch[k^1]].fa=y;
    tr[y].fa=x;tr[x].ch[k^1]=y;
    pushup(y);pushup(x);
inline void splay(int x)
    int y,z;
    push(x);
    while(!root(x))
        y=tr[x].fa,z=tr[y].fa;
        if(!root(y))(tr[z].ch[0]==y)^(tr[y].ch[0]==x)?rotate(x):rotate(y);
        rotate(x);
    pushup(x);
inline void access(int x)for(int y=0;x;y=x,x=tr[x].fa)splay(x);tr[x].ch[1]=y;pushup(x);
inline void makeroot(int x)
    access(x);splay(x);pushr(x);
inline void split(int x,int y)
    makeroot(x);access(y);splay(y);
inline void link(int x,int y)
    makeroot(x);tr[x].fa=y;
inline void add(int x,int y)
    e[++tot].to=y;
    e[tot].next=head[x];
    head[x]=tot;
inline void dfs(int u,int fa) 
    dep[u]=dep[fa]+1;
    for(register int i=head[u] ; i ; i=e[i].next) if(e[i].to!=fa) dfs(e[i].to,u);

int main()
//    link(1,2);link(1,3);
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;++i)
        scanf("%d%d",&a[i],&b[i]);
        add(a[i],b[i]);add(b[i],a[i]);
    dep[0]=0;
    dfs(1,0);
    //printf("Case:1#\n");
    dep[0]=2147483647;
//    printf("Case:3#\n");
    for(int i=1;i<n;++i)/*printf("Step%d %d %d\n",i,a[i],b[i]),*/link(a[i],b[i])/*,printf("Case:4#%d\n",i)*/;
//    printf("Case:2#\n");
    for(int i=1;i<=m;++i)
        scanf("%d%d",&opt,&f);
        if(!opt)makeroot(f),tr[f].col^=1;
        else
            split(1,f);
            printf("%d\n",tr[f].id==0?-1:tr[f].id);
        
    return 0;

 

地理中考:

...
int main()
    int grades=0,rp=0;
    while(727)
        rp++;grades++;
    
    return 0;
    

 

以上是关于题解QTree3的主要内容,如果未能解决你的问题,请参考以下文章

SPOJ QTREE3 - Query on a tree again!

P4116 Qtree3

QTREE3 - Query on a tree again! 树链

Java 求解划分字母区间

微信小程序代码片段

VSCode自定义代码片段——CSS选择器