题目

在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下

两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个

结点,可以打多次标记。)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖

先)你能帮帮他吗?

分析

此题有很多种方法

暴力+并查集

转了别人的

考虑离线处理。

我们将所有的操作倒序处理,利用并查集进行维护。对于一个修改操

作(即失去标记),相当于将这一联通块块与它父亲的联通块合并。对于

一个查询操作,直接查询所在的块的父亲即可。

实现中有些细节需要注意,比如每个点可能会被标记多次,所以要以

最早的被标记时间做为“失去标记”的时间。

时间复杂度为O(n + qα(n))

DFN序+线段树

首先搞一遍dfn序,

接着发现,在用一棵子树中,dfn序都是相邻的。

好了,线段树修改查询。

树链剖分

单独修改、查询1到num的路径。

裸题一枚。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=100005;
using namespace std;
int tree[N*6],top[N],d[N],size[N],deep[N],son[N],fa[N],n,m,tot,ans;
int last[N*2],next[N*2],to[N*2],bef[N],aft[N];
void bj(int x,int y)
{
next[++tot]=last[x];
last[x]=tot;
to[tot]=y;
}
void dg(int x,int y)
{
size[x]=1;
int mx=0;
for(int i=last[x];i;i=next[i])
{
int j=to[i];
if(j!=y)
{
deep[j]=deep[x]+1;
fa[j]=x;
dg(j,x);
size[x]+=size[j];
if(size[j]>mx)
{
mx=size[j];
son[x]=j;
}
}
}
}
int dg1(int x,int y)
{
d[++tot]=x;
aft[x]=tot;
bef[tot]=x;
if(!top[x])
top[x]=x;
if(son[x])
{
top[son[x]]=top[x];
dg1(son[x],x);
}
for(int i=last[x];i;i=next[i])
{
int j=to[i];
if(j!=y && j!=son[x])
{
dg1(j,x);
}
}
}
int put(int v,int l,int r,int x)
{
if(l==r)
{
tree[v]=bef[x];
return 0;
}
int mid=(l+r)/2;
if(x<=mid)
{
put(v*2,l,mid,x);
}
else
put(v*2+1,mid+1,r,x);
tree[v]=deep[tree[v*2]]>deep[tree[v*2+1]]?tree[v*2]:tree[v*2+1];
}
int find(int v,int l,int r,int x,int y)
{
if(l==x && r==y)
{
ans=deep[ans]>deep[tree[v]]?ans:tree[v];
return 0;
}
int mid=(l+r)/2;
if(y<=mid)
{
find(v*2,l,mid,x,y);
}
else
if(mid<x)
{
find(v*2+1,mid+1,r,x,y);
}
else
{
find(v*2,l,mid,x,mid);
find(v*2+1,mid+1,r,mid+1,y);
}
tree[v]=deep[tree[v*2]]>deep[tree[v*2+1]]?tree[v*2]:tree[v*2+1];
}
int main()
{
freopen("4604.in","r",stdin);
freopen("4604.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
bj(x,y);
bj(y,x);
}
deep[1]=1;
dg(1,0);
top[1]=1;
tot=0;
dg1(1,0);
put(1,1,n,aft[1]);
scanf("\n");
for(int i=1;i<=m;i++)
{
int c;
int x,y;
c=getchar();
while((c!='Q')&&(c!='C'))c=getchar();
scanf("%d\n",&x);
if(c=='C')
{
put(1,1,n,aft[x]);
}
else
{
ans=0;
while(top[x]!=top[1])
{
find(1,1,n,aft[top[x]],aft[x]);
x=fa[top[x]];
}
find(1,1,n,aft[1],aft[x]);
printf("%d\n",ans);
}
}
}

【bzoj4551】【NOIP2016模拟7.11】树的更多相关文章

  1. NOIP2016模拟赛三 Problem B: 神奇的树

    题面 Description 有一棵神奇的树.这棵树有N个节点,在每个节点上都有宝藏,每个宝藏价值V[i]金币:对于每条边,每经过一次都要花费C[i]金币. 值得注意的是,每个宝藏只能领取一次(也可以 ...

  2. JZOJ 4611. 【NOI2016模拟7.11】接水问题 (贪心+A*+可持久化线段树)

    Description: https://gmoj.net/senior/#main/show/4611 题解: 先把A从大到小排序,最小的由排序不等式显然. 考虑类似第k短路的A*的做法. 定义状态 ...

  3. 「考试」noip模拟9,11,13

    9.1 辣鸡 可以把答案分成 每个矩形内部连线 和 矩形之间的连线 两部分 前半部分即为\(2(w-1)(h-1)\),后半部分可以模拟求(就是讨论四种相邻的情况) 如果\(n^2\)选择暴力模拟是有 ...

  4. vue 模拟下拉树

    // 使用vue 做表格部分其他部分暂不修改 var app = new Vue({ el: "#freightTbl", watch: { //监听表格数据的变化[使用 watc ...

  5. [转载]如何在C++03中模拟C++11的右值引用std::move特性

    本文摘自: http://adamcavendish.is-programmer.com/posts/38190.htm 引言 众所周知,C++11 的新特性中有一个非常重要的特性,那就是 rvalu ...

  6. 串门赛: NOIP2016模拟赛——By Marvolo 丢脸记

    前几天liu_runda来机房颓废,顺便扔给我们一个网址,说这上面有模拟赛,让我们感兴趣的去打一打.一开始还是没打算去看一下的,但是听std说好多人都打,想了一下,还是打一打吧,打着玩,然后就丢脸了. ...

  7. 6424. 【NOIP2019模拟2019.11.13】我的订书机之恋

    题目描述 Description Input Output Sample Input 见下载 Sample Output 见下载 Data Constraint 题解 lj题卡线段树 求出每个右端点往 ...

  8. [CSP-S模拟测试]:砍树(数学+模拟)

    题目传送门(内部题1) 输入格式 第一行两个整数$n$,$k$,代表树苗的数量和最大看书的总长度.第二行n个整数$a_i$,代表林先森希望每棵树苗的最终高度. 输出格式 一行一个整数,代表最大可能的d ...

  9. 2019.8.1 NOIP模拟测试11 反思总结

    延迟了一天来补一个反思总结 急匆匆赶回来考试,我们这边大家的状态都稍微有一点差,不过最后的成绩总体来看好像还不错XD 其实这次拿分的大都是暴力[?],除了某些专注于某道题的人以及远程爆踩我们的某学车神 ...

随机推荐

  1. import 和组件库按需引入

    概述 今天查资料查到了一些有趣的东西,记录下来,供以后开发时参考,相信对其他人也有用. 参考资料: import.require.export.module.exports 混合使用详解 从 impo ...

  2. python调用c/c++时传递结构体参数

    背景:使用python调用linux的动态库SO文件,并调用里边的c函数,向里边传递结构体参数.直接上代码 //test1.c # include <stdio.h> # include ...

  3. 系统用户与用户组管|chfn、密码管理、身份切换、sudo

    2 系统用户与用户组管理 GID为GroupId,即组ID,用来标识用户组的唯一标识符 UID为UserId,即用户ID,用来标识每个用户的唯一标示符 /etc/passwd /etc/shadow ...

  4. 63 (OC)* NSAutoreleasePool 自动释放池

    目录 0:ARC 1: 自动释放池 2:NSAutoreleasePool实现原理 3:autorelease 方法 4: Runloop和Autorelease的关系 5: Using Autore ...

  5. python 并发编程 多进程 互斥锁与join区别

    互斥锁与join 互斥锁和join都可以把并发变成串行 以下代码是用join实现串行 from multiprocessing import Process import time import js ...

  6. JAVA第四周总结与实验2

    实验二 Java简单类与对象 一. 实验目的 (1) 掌握类的定义,熟悉属性.构造函数.方法的作用,掌握用类作为类型声明变量和方法返回值: (2) 理解类和对象的区别,掌握构造函数的使用,熟悉通过对象 ...

  7. 虚拟机上首次安装Ubuntu后 root密码设置

    虚拟机下安装ubuntu后root密码设置 问题描述: 在虚拟机下安装了ubuntu中要输入用户名,一般情况下大家都会输入一个自己的网名或绰号之类的,密码也在这时设置过了. 但是当安装成功之后,使用命 ...

  8. Linux文件与目录操作 ls 命令(2)

    说文件操作是最频繁地操作也不为过,在Linux中,使用ls命令可以列出当前目录中所有内容,本篇就先说说ls命令.本文所说的文件指文件和目录. ls命令常用选项 -a:显示指定目录下所有子目录与文件,包 ...

  9. [BZOJ4444] [Luogu 4155] [LOJ 2007] [SCOI2015]国旗计划(倍增)

    [BZOJ4444] [Luogu 4155] [LOJ 2007] [SCOI2015]国旗计划(倍增) 题面 题面较长,略 分析 首先套路的断环为链.对于从l到r的环上区间,若l<=r,我们 ...

  10. linux的mv、cp 命令

    用mv命令1.作用mv命令来为文件或目录改名或将文件由一个目录移入另一个目录中.该命令等同于DOS系统下的ren和move命令的组合.它的使用权限是所有用户.2.格式mv [options] 源文件或 ...