[bzoj4551][TJOI&HEOI2016]树

题目大意

一颗树,除根节点外初始都是白点,根节点是黑点。

每次染黑一个结点或者询问一个结点的最近黑色祖先。

倒序处理

倒着做,于是每次是染白一个结点。

那么就并查集搞呀!

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=100000+10;
struct dong{
    int x,ans;
    bool p;
} ask[maxn];
int fa[maxn],father[maxn],bz[maxn];
int h[maxn],go[maxn*2],next[maxn*2];
int i,j,k,l,t,n,m,tot;
char ch;
void add(int x,int y){
    go[++tot]=y;
    next[tot]=h[x];
    h[x]=tot;
}
void dfs(int x,int y){
    father[x]=y;
    int t=h[x];
    while (t){
        if (go[t]!=y) dfs(go[t],x);
        t=next[t];
    }
}
void dg(int x,int y){
    if (!bz[x]) fa[x]=father[x];
    int t=h[x];
    while (t){
        if (go[t]!=y) dg(go[t],x);
        t=next[t];
    }
}
int getfa(int x){
    return fa[x]?fa[x]=getfa(fa[x]):x;
}
char get(){
    char ch=getchar();
    while (ch!=‘Q‘&&ch!=‘C‘) ch=getchar();
    return ch;
}
int main(){
    scanf("%d%d",&n,&m);
    fo(i,1,n-1){
        scanf("%d%d",&j,&k);
        add(j,k);add(k,j);
    }
    dfs(1,0);
    bz[1]=1;
    fo(i,1,m){
        ch=get();
        scanf("%d",&j);
        if (ch==‘Q‘){
            ask[i].p=1;
            ask[i].x=j;
        }
        else{
            ask[i].x=j;
            bz[j]++;
        }
    }
    dg(1,0);
    fd(i,m,1)
        if (ask[i].p) ask[i].ans=getfa(ask[i].x);
        else{
            bz[ask[i].x]--;
            if (!bz[ask[i].x]) fa[ask[i].x]=father[ask[i].x];
        }
    fo(i,1,m)
        if (ask[i].p) printf("%d\n",ask[i].ans);
}
时间: 2024-10-16 08:26:28

[bzoj4551][TJOI&HEOI2016]树的相关文章

bzoj4551[Tjoi2016&amp;Heoi2016]树

bzoj4551[Tjoi2016&Heoi2016]树 题意: 给个根节点为1的n点树,初始时节点1标记,Q个操作,每次可以标记一个点或求一个点最近一个标记了的祖先. 题解: 链剖可以写,当正解应该是并查集.离线读入所有操作,累加每个节点的标记次数,之后所有未被标记的节点向其父亲节点连边,然后倒着来,如果操作是询问则输出这个节点在并查集中的根节点,如果是标记则将该节点的标记数减1,一旦这个节点的标记数减到了0,就让它向父亲节点连边. 代码: 1 #include <cstdio> 2

【BZOJ4551】[Tjoi2016&amp;Heoi2016]树 并查集

[BZOJ4551][Tjoi2016&Heoi2016]树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个 结点,可以打多次标记.)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖 先)你能帮帮他吗? Input 输入第一行两个正整数N和Q分别表示节点个数和操作次数接下来N-1行

dtoj4542. 「TJOI / HEOI2016」字符串

4542. 「TJOI / HEOI2016」字符串 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为 $ n $ 的字符串 $ s $,和 $ m $ 个问题.佳媛姐姐必须正确回答这 $ m $ 个问题,才能打开箱子拿到礼物,升职加薪,出任 CEO,嫁给高富帅,走上人生巅峰.每个问题均有 $a, b, c, d$ 四个参数,问你子串 $s[a \ldots b]$ 的所有子串和 $s[c \ldots d]$ 的最长公共前缀的长度的最

AC日记——#2057. 「TJOI / HEOI2016」游戏 LOJ

#2057. 「TJOI / HEOI2016」游戏 思路: 最大流: 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f #define maxn 2000005 int n,m,s,t,que[maxn],deep[maxn],toth,totl,F[max

【TJOI&amp;HEOI2016】【Bzoj4551】树

这道题是可以用树链剖分来做的,但其实有比它更加简单的做法--并查集. 可以想到,这类题的一种常见做法是离线处理,先全部读入,再从后往前处理,每次遇到标记操作,就把这个点的标记次数减一,到零以后就把这个点的前继连到它的父亲上. 然后再倒序输出答案即可. Code: 1 #include<cstdio> 2 #include<vector> 3 using namespace std; 4 const int maxn=100010; 5 struct data{ 6 char str

【bzoj4551】[Tjoi2016&amp;Heoi2016]树 离线处理+并查集

题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个结点,可以打多次标记.)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖先)你能帮帮他吗? 输入 输入第一行两个正整数N和Q分别表示节点个数和操作次数接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v有一条有向边接下来Q行,形如"oper

BZOJ 4551: [Tjoi2016&amp;Heoi2016]树

Description 一棵树有黑白点,求最近黑点祖先. Solution 树链剖分. 我居然敲了15min? Code /************************************************************** Problem: 4551 User: BeiYu Language: C++ Result: Accepted Time:1972 ms Memory:11952 kb ***************************************

[bzoj4552][TJOI&amp;HEOI2016]排序

题目大意 有一个n的排列,进行m次操作,每次操作是将一个区间升序或降序排序. 请你输出m次操作后第p个位置的值. 二分答案 题解好机智! 我们二分答案x,然后就是判断a[p]>=x? 把原序列转化为01序列,0表示小于x,1表示大于等于x. 那么区间升序排序其实就是把0全放前面,1都放后面. 用线段树兹瓷区间赋值就好了. 然后只需要维护区间0的个数. #include<cstdio> #include<algorithm> #define fo(i,a,b) for(i=a;

HEOI2016 树

传送门 这道题还是很简单的,可以树剖,然后还有看大佬暴力模拟AC的????!! 我们就执行俩操作,一个是单点修改,这个随便修,然后就是查询一个点,离他最近的被打过标记过的祖先.这个可以这么想,我们先query这个点所在链上的权值,如果>0就说明这条链上肯定是有至少一个被改过的点的.然后直接在区间之内左右二分即可. (我不会告诉你我一开始想的是什么主席树维护的) 然后树剖写了这么多,就是要注意两点: 1.树剖和线段树千万别写错了-- 2.一定要分清原顺序和dfs序,线段树维护的是dfs序,但是实际