BZOJ 4551: [Tjoi2016&Heoi2016]树

Description

一棵树有黑白点,求最近黑点祖先。

Solution

树链剖分。

我居然敲了15min?

Code

/**************************************************************
    Problem: 4551
    User: BeiYu
    Language: C++
    Result: Accepted
    Time:1972 ms
    Memory:11952 kb
****************************************************************/

#include <bits/stdc++.h>
using namespace std;

#define mpr make_pair
#define x first
#define y second
#define debug(a) cout<<(#a)<<"="<<a<<" "
//#define lc(o) ch[o][0]
//#define rc(o) ch[o][1]
#define lc (o<<1)
#define rc (o<<1|1)
#define mid ((l+r)>>1)

typedef long long LL;
typedef pair<int,int> pr;
typedef vector<int> Vi;
typedef vector<LL> Vl;
typedef vector<string> Vs;
const int N = 100500;
const int M = N<<2;
const int oo = 0x3fffffff;
const LL  OO = 1e18;

inline LL in(LL x=0,char ch=getchar(),int v=1) {
    while(ch>‘9‘ || ch<‘0‘) v=ch==‘-‘?-1:v,ch=getchar();
    while(ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x*v;
}
/*end*/

int n,q;
int p[N],rp[N],mk[N];

struct SegmentTree {
    int d[M];

    void Modify(int o,int l,int r,int x) {
        if(l==r) { d[o]=l;return; }
        if(x<=mid) Modify(lc,l,mid,x);
        else Modify(rc,mid+1,r,x);
        d[o]=max(d[lc],d[rc]);
    }
    int Query(int o,int l,int r,int L,int R) {
        if(L<=l && r<=R) return d[o];
        int res=0;
        if(L<=mid) res=max(res,Query(lc,l,mid,L,R));
        if(R>mid) res=max(res,Query(rc,mid+1,r,L,R));
        return res;
    }
}py;

namespace Tree {
    int cnt;
    int d[N],f[N],top[N],sz[N],sn[N];
    vector<int> g[N];

    void AddEdge(int u,int v) { g[u].push_back(v),g[v].push_back(u); }
    void DFS1(int u,int fa) {
        d[u]=d[fa]+1,sz[u]=1,sn[u]=0;
        for(int i=0,v;i<(int)g[u].size();i++) if((v=g[u][i])!=fa) {
            DFS1(v,u),sz[u]+=sz[v],f[v]=u;
            if(!sn[u] || sz[sn[u]]<sz[v]) sn[u]=v;
        }
    }
    void DFS2(int u,int fa,int tp) {
        p[u]=++cnt,rp[cnt]=u,top[u]=tp;
        if(sn[u]) DFS2(sn[u],u,tp);
        for(int i=0,v;i<(int)g[u].size();i++) if((v=g[u][i])!=fa && v!=sn[u])
            DFS2(v,u,v);
    }
    void init() {
        DFS1(1,1),DFS2(1,1,1);
        py.Modify(1,1,n,1);
        mk[1]=1;
    }
    int Query(int u) {
        int f1=top[u],res=0;
        for(;u;) {
            res=py.Query(1,1,n,p[f1],p[u]);
            if(res) return rp[res];
            u=f[f1],f1=top[u];
        }return 1;
    }
}

int main() {
    n=in(),q=in();
    for(int i=1;i<n;i++) {
        int x=in(),y=in();
        Tree::AddEdge(x,y);
    }
    Tree::init();
    for(int i=1;i<=q;i++) {
        char opt[15];int x;
        scanf("%s",opt);
        if(opt[0]==‘C‘) {
            x=in();
            if(!mk[x]) mk[x]=1,py.Modify(1,1,n,p[x]);
        } else {
            x=in();
            printf("%d\n",Tree::Query(x));
        }
    }return 0;
}

  

时间: 2024-11-08 21:58:15

BZOJ 4551: [Tjoi2016&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行

[BZOJ] 4552: [Tjoi2016&amp;Heoi2016]排序 #二分+线段树+算法设计策略

4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 1451  Solved: 734[Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,r

BZOJ 4553 Tjoi2016&amp;Heoi2016 序列

Tjoi2016&Heoi2016序列 Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值 可能会变化,但同一个时刻最多只有一个值发生变化.现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你 ,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可 .注意:每种变化最多只有一个值发生变化.在样例输入1中,所有的变化是: 1 2 3 2 2 3 1 3 3 1 1 31 2 4

bzoj 4555 [Tjoi2016&amp;Heoi2016]求和 NTT 第二类斯特林数 等比数列求和优化

[Tjoi2016&Heoi2016]求和 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 679  Solved: 534[Submit][Status][Discuss] Description 在2016年,佳媛姐姐刚刚学习了第二类斯特林数,非常开心. 现在他想计算这样一个函数的值: S(i, j)表示第二类斯特林数,递推公式为: S(i, j) = j ∗ S(i − 1, j) + S(i − 1, j − 1), 1 <= j &l

bzoj 4556: [Tjoi2016&amp;Heoi2016]字符串

二分ans,二分区间长度,st表查,最后主席树判断. 这题最大收获学到了一个nb的卡常技巧,主席树元素个数为0直接返回,不敢相信快了一倍. 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define N 200005 6 using namespace std; 7 inline int read() 8 { 9 int p=0;cha

bzoj 4552: [Tjoi2016&amp;Heoi2016]排序

Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q 位置上的数字. Input 输入数据的第一行为两个整数n和m.n表示序列的长度,m表示局部排序的次数.1 <= n, m <= 10^

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

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

bzoj 4552 [Tjoi2016&amp;Heoi2016]排序——二分答案

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4552 二分答案,把 >= mid 的设成1.< mid 的设成0,之后排序就变成区间赋值了. #include<cstdio> #include<cstring> #include<algorithm> #define ls Ls[cr] #define rs Rs[cr] using namespace std; const int N=1e5+5,