[CF343D Round#200 Div.1]Water Tree——[树链剖分]

【原题】
Mad scientist Mike has constructed a rooted tree, which consists of n n vertices. Each vertex is a reservoir which can be either empty or filled with water.

The vertices of the tree are numbered from 1 to n n with the root at vertex 1. For each vertex, the reservoirs of its children are located below the reservoir of this vertex, and the vertex is connected with each of the children by a pipe through which water can flow downwards.

Mike wants to do the following operations with the tree:

Fill vertex v v with water. Then v v and all its children are filled with water.
Empty vertex v v . Then v v and all its ancestors are emptied.
Determine whether vertex v v is filled with water at the moment.

Initially all vertices of the tree are empty.Mike has already compiled a full list of operations that he wants to perform in order. Before experimenting with the tree Mike decided to run the list through a simulation. Help Mike determine what results will he get after performing all the operations.

【题目翻译】

疯狂科学家Mike培养了一颗有根树,由n个节点组成。每个节点是一个要么装满水要么为空的贮水容器. 树的节点用1~n编号,其中根节点为1.对于每个节点的容器,其子节点的容器均在这一容器下方,并且每个节点都由一根可以向下流水的管道与其子节点连接. Mike想要对这棵树做以下操作:

将节点v注满水. 这样v和其子节点都会充满水.
将节点v置空. 这样v及其祖先节点(从v到根节点的路径)都会被置空.
查询当前节点v是否充满水.
初始时,所有节点都为空. Mike已经制定好了他的操作顺序. 在对树进行实验前,他决定先模拟一下操作. 请你帮助Mike得出他操作后的结果.

【输入格式】
第一行为一个整数n(1<=n<=500000),为树的节点数;
下面的n-1行为两个空格隔开的整数ai,bi(1<=ai, bi<=n),为树的边;
下一行为一个整数q(1<=q<=500000),为操作数;接下来q行,两个空格隔开的整数ci(1<=ci<=3),vi(1<=vi<=n),其中ci为操作类型(已给出),vi为被操作的节点.
这意味着给出的图为一棵树.

【输出格式】
对于每一次操作3,如果节点v充满水,单独输出一行1,如果节点v为空,单独输出一行0. 按照操作输入的顺序输出.

S a m p l e &ThickSpace; I n p u t Sample\;Input SampleInput

5
1 2
5 1
2 3
4 2
12
1 1
2 3
3 1
3 2
3 3
3 4
1 2
2 4
3 1
3 3
3 4
3 5

S a m p l e &ThickSpace; O u t p u t Sample\;Output SampleOutput

0
0
0
1
0
1
0
1

【题意分析】
蒟蒻远古时期做的一道题目。今天才记起来qwq

三种树上操作:修改子树,修改路径,查询单点。

考虑树链剖分,线段树采用区间覆盖(就是把+=改成=)
因为我比较傻就把查询写成了线段树单点查询~~

这道题值得一提,因为我上上下下WA了至少10次,求助多个大佬均无果。
然后,FancyKiller 大奆佬跟我讲:

前向星没开两倍。

orz。。。

Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAX 500005
using namespace std;

struct Front_Link_Star{
    int next,to;
}edge[MAX << 1];

int tree[MAX << 2],lazy[MAX << 2],top[MAX],father[MAX],size[MAX];
int son[MAX],depth[MAX],head[MAX],id[MAX],n,m,cnt,dfn,ans;

inline void Add_Edge(int u,int v){
    edge[++cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt;
}

inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while (!isdigit(ch)){if (ch=='-')w=-1;ch=getchar();}
    while (isdigit(ch)){s=(s << 3)+(s << 1)+ch-'0';ch=getchar();}
    return s*w;
}

inline void push_down(int now,int tl,int tr){
    int mid=(tl+tr) >> 1;
    tree[now << 1]=lazy[now]*(mid-tl+1);
    tree[now << 1|1]=lazy[now]*(tr-mid);
    lazy[now << 1]=lazy[now];
    lazy[now << 1|1]=lazy[now];
    lazy[now]=-1;
}//覆盖,改成赋值。

inline void build(int now,int tl,int tr){
    lazy[now]=-1;
    if (tl==tr)return;
    int mid=(tl+tr) >> 1;
    build(now << 1,tl,mid);
    build(now << 1|1,mid+1,tr);
}

inline void update(int now,int tl,int tr,int left,int right,int change){
    if (right<tl||tr<left)return;
    if (left<=tl&&tr<=right){
        tree[now]=change*(tr-tl+1);
        lazy[now]=change;
        return;
    }
    if (lazy[now]!=-1)push_down(now,tl,tr);
    int mid=(tl+tr) >> 1;
    update(now << 1,tl,mid,left,right,change);
    update(now << 1|1,mid+1,tr,left,right,change);
    tree[now]=tree[now << 1]+tree[now << 1|1];
}

inline void query(int now,int tl,int tr,int position){
    if (tl>position||position>tr)return;
    if (tl==tr){
        ans=tree[now];
        return;
    }
    if (lazy[now]!=-1)push_down(now,tl,tr);
    int mid=(tl+tr) >> 1;
    query(now << 1,tl,mid,position);
    query(now << 1|1,mid+1,tr,position);
}//基本操作么没什么好说的

inline void Modify_Tree(int x,int change){
    update(1,1,n,id[x],id[x]+size[x]-1,change);
}//子树修改

inline void Modify_Range(int x,int y,int change){
    while (top[x]!=top[y]){
        if (depth[top[x]]<depth[top[y]])swap(x,y);
        update(1,1,n,id[top[x]],id[x],change);
        x=father[top[x]];
    }
    if (depth[x]>depth[y])swap(x,y);
    update(1,1,n,id[x],id[y],change);
}

inline void DFS1(int now,int fa,int d){
    father[now]=fa;
    depth[now]=d;
    size[now]=1;
    int maxson=-1;
    for (register int i=head[now];i;i=edge[i].next){
        int v=edge[i].to;
        if (v==father[now])continue;
        DFS1(v,now,d+1);
        size[now]+=size[v];
        if (maxson<size[v]){
            maxson=size[v];
            son[now]=v;
        }
    }
}

inline void DFS2(int now,int top_heavy){
    id[now]=++dfn;
    top[now]=top_heavy;
    if (!son[now])return;
    DFS2(son[now],top_heavy);
    for (register int i=head[now];i;i=edge[i].next){
        int v=edge[i].to;
        if (v!=father[now]&&v!=son[now])DFS2(v,v);
    }
}//树链剖分

int main(){
    n=read();
    for (register int i=1;i<n;i++){
        int x=read(),y=read();
        Add_Edge(x,y);
        Add_Edge(y,x);
    }
    DFS1(1,0,1);
    DFS2(1,1);
    build(1,1,n);
    m=read();
    while (m--){
        int type=read(),x=read();
        if (type==1)Modify_Tree(x,1);
        if (type==2)Modify_Range(1,x,0);
        if (type==3){
            ans=0;
            query(1,1,n,id[x]);//直接暴力进线段树查询
            printf("%d\n",ans);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值