CF877E Danil and a Part-time Job 线段树维护dfs序

\(\color{#0066ff}{题目描述}\)

有一棵 n 个点的树,根结点为 1 号点,每个点的权值都是 1 或 0
共有 m 次操作,操作分为两种

get 询问一个点 x 的子树里有多少个 1
pow 将一个点 x 的子树中所有节点取反

对于每个 get 给出答案

\(\color{#0066ff}{输入格式}\)

第一行一个整数 n
第二行共 n?1 个整数,第 i 个数 \(x_i\) 表示 \(x_i\) 是 i+1 的父亲,
第三行给出每个点的初始权值
第四行一个整数 m
接下来 m 行为操作类型和位置

\(\color{#0066ff}{输出格式}\)

对于每个 get 给出答案

\(\color{#0066ff}{输入样例}\)

4
1 1 1
1 0 0 1
9
get 1
get 2
get 3
get 4
pow 1
get 1
get 2
get 3
get 4

\(\color{#0066ff}{输出样例}\)

2
0
0
1
2
1
1
0

\(\color{#0066ff}{数据范围与提示}\)

\(1\leq n \leq 200000,1\leq q\leq 200000\)

\(\color{#0066ff}{题解}\)

线段树维护dfs序

同一子树内dfs序连续

线段树上修改查询即可

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define _ 0
#define LL long long
#ifndef olinr
inline char getc()
{
    static char buf[100001],*p1=buf,*p2=buf;
    return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100001,stdin),p1==p2)? EOF:*p1++;
}
#else
#define getc() getchar()
#endif
inline LL in()
{
    LL x=0,f=1; char ch;
    while(!isdigit(ch=getc()))(ch=='-')&&(f=-f);
    while(isdigit(ch)) x=x*10+(ch^48),ch=getc();
    return x*f;
}
const int max=205005;
int val[max],dfn[max],redfn[max],siz[max];
class SGT
{
    private:
        struct node
        {
            int l,r;
            int val;
            node* ch[2];
            bool tag;
            node(int l,int r,int val,int tag):l(l),r(r),val(val),tag(tag){}
            void upd() {val=ch[0]->val+ch[1]->val;}
            int mid() {return (l+r)>>1;}
            int siz() {return r-l+1;}
            void dwn()
            {
                if(!tag) return;
                ch[0]->val=ch[0]->siz()-ch[0]->val;
                ch[1]->val=ch[1]->siz()-ch[1]->val;
                ch[0]->tag^=1;
                ch[1]->tag^=1;
                tag=0;
            }
        };
        typedef node* nod;
    public:
        nod root;
        void build(nod &o,int l,int r)
        {
            o=new node(l,r,0,0);
            if(l==r) return (void)(o->val=val[redfn[l]]);
            build(o->ch[0],l,o->mid());
            build(o->ch[1],o->mid()+1,r);
            o->upd();
        }
        void lazy(nod o,int l,int r)
        {
            if(o->r<l||o->l>r) return;
            if(l<=o->l&&o->r<=r)
            {
                o->tag^=1;
                o->val=o->siz()-o->val;
                return;
            }
            o->dwn();
            lazy(o->ch[0],l,r),lazy(o->ch[1],l,r);
            o->upd();
        }
        int query(nod o,int l,int r)
        {
            if(o->r<l||o->l>r) return 0;
            if(l<=o->l&&o->r<=r) return o->val;
            o->dwn();
            return query(o->ch[0],l,r)+query(o->ch[1],l,r);
        }
}s;
struct node
{
    int to;
    node *nxt;
    node(int to,node *nxt):to(to),nxt(nxt){}
};
typedef node* nod;
nod head[max];
int cnt;
void add(int from,int to)
{
    nod t=new node(to,head[from]);
    head[from]=t;
}
void dfs(int x,int f)
{
    siz[x]=1;
    dfn[x]=++cnt;
    redfn[cnt]=x;
    for(nod i=head[x];i;i=i->nxt)
        if(i->to!=f) dfs(i->to,x),siz[x]+=siz[i->to];
}
int n,m;

int main()
{
    n=in(); int x;
    for(int i=1;i<=n-1;i++) x=in(),add(x,i+1),add(i+1,x);
    for(int i=1;i<=n;i++) val[i]=in();
    dfs(1,0);
    s.build(s.root,1,n);
    m=in();
    char ch;
    while(m--)
    {
        while(!isalpha(ch=getc()));
        x=in();
        if(ch=='g') printf("%d\n",s.query(s.root,dfn[x],dfn[x]+siz[x]-1));
        else s.lazy(s.root,dfn[x],dfn[x]+siz[x]-1);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/olinr/p/10081036.html

时间: 2024-10-23 06:54:32

CF877E Danil and a Part-time Job 线段树维护dfs序的相关文章

BZOJ 3779 重组病毒 LCT+线段树维护DFS序

题目大意:给定一棵树,初始每个点都有一个颜色,支持三种操作: 1.将某个点到根的路径上所有点染上一种新的颜色 2.将某个点到根的路径上所有点染上一种新的颜色,然后把根设为这个点 3.定义一个点的代价为这个点到根路径上颜色的种类数,求某个点子树中所有点代价的平均值 我真是炖了狗了-- 容易发现这玩应就是个LCT,操作1就是Access,操作2就是Move_To_Root,代价就是一个点到根路径上的虚边数量+1 我们用LCT模拟上述操作,用线段树维护DFS序维护信息,一旦LCT中出现了虚实边的切换,

CodeForces 343D 线段树维护dfs序

给定一棵树,初始时树为空 操作1,往某个结点注水,那么该结点的子树都注满了水 操作2,将某个结点的水放空,那么该结点的父亲的水也就放空了 操作3,询问某个点是否有水 我们将树进行dfs, 生成in[u], 访问结点u的时间戳,out[u],离开结点u的时间戳 每个结点的in值对应在线段树中的区间的一点 那么对于操作1, 只要将区间[in[u],out[u]] 的值都改为1, 但是如果区间[in[u],out[u]] 原先存在为0的点,那么父区间肯定是空的,这个操作不能 改变父区间的状态,所以需要

CCPC河南省赛B-树上逆序对| 离线处理|树状数组 + 线段树维护逆序对 + dfs序 + 离散化

B题地址:树上逆序对 有两个思路 方法一:线段树离线 + 树状数组或者线段树维护区间和 0:离散化,离线存储输入的operation操作序列. ①:先线段树在dfs序上离线处理好整一棵树:在dfs序上先查询"加入当前结点的逆序对权值和"并记录,再加入当前这个节点:dfs完毕后,就已经记录好每个结点的dfs序出入时间戳(转化成区间问题了)和每个 ②:使用树状数组或者新的线段树在dfs序上插入逆序对权值 为什么能这样呢?因为dfs序维护了每个结点遍历的顺序,每个结点的dfs序时间戳肯定比它

2016shenyang-1002-HDU5893-List wants to travel-树链剖分+线段树维护不同区间段个数

肯定先无脑树链剖分,然后线段树维护一段区间不同个数,再维护一个左右端点的费用. 线段树更新,pushDown,pushUp的时候要注意考虑链接位置的费用是否相同 还有就是树链剖分操作的时候,维护上一个更新的位置的费用. 总之就是出现区间合并,就考虑总数是否要减一 好想不好写 //场上根本写不完啊 1 /*--------------------------------------------------------------------------------------*/ 2 3 #inc

[BZOJ 1018] [SHOI2008] 堵塞的交通traffic 【线段树维护联通性】

题目链接:BZOJ - 1018 题目分析 这道题就说明了刷题少,比赛就容易跪..SDOI Round1 Day2 T3 就是与这道题类似的..然而我并没有做过这道题.. 这道题是线段树维护联通性的经典模型. 我们线段树的一个节点表示一个区间的联通性,有 6 个 bool 值,表示这个区间的 4 个角上的点之间的联通性. 然后用两个子区间的联通性和两个子区间之间的连边情况合并出整个区间的联通性. 修改某条边时,先在边的数组中修改,然后从这条边所在的点的线段树叶子开始向上 Update . 询问两

Codeforces GYM 100114 D. Selection 线段树维护DP

D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Description When selecting files in an application dialog, Vasya noted that he can get the same selection in different ways. A simple mouse click selects a sing

Subsequence Count 2017ccpc网络赛 1006 dp+线段树维护矩阵

Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string.There are two types of queries:1. Flipping the bits (i.e., changing all 1 to 0 and 0 to 1) between l and r (inclusive).2. Counting the

HDU 6155 Subsequence Count 线段树维护矩阵

Subsequence Count Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others) Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string. There are two types of querie

HDU 5068 Harry And Math Teacher( 矩阵乘法 + 线段树维护 )

HDU 5068 Harry And Math Teacher( 矩阵乘法 + 线段树维护 ) 题意: 首先是这题题意理解错误,,其次是这题无法理解状态... 已经不是英文有多烂的情况了,是中文没学好啊.....大学不学语文才是真正的硬伤啊 题目意思 有一个城堡有很多层楼, 每层楼有2个门,每个门里面又有两个楼梯,可以通往上一层的两个门 问,从x层楼到y层楼有多少中方法(不能返回) 具体看图吧,,,已经不会说话了 1 #include <cstdio> 2 #include <cstri