• CF343D Water Tree


    CF343D Water Tree

    题目描述

    Mad scientist Mike has constructed a rooted tree, which consists of nn 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 nn 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:

    1. Fill vertex vv with water. Then vv and all its children are filled with water.
    2. Empty vertex vv . Then vv and all its ancestors are emptied.
    3. Determine whether vertex vv 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.

    输入格式

    The first line of the input contains an integer nn ( 1<=n<=5000001<=n<=500000 ) — the number of vertices in the tree. Each of the following n-1n−1 lines contains two space-separated numbers a_{i}a**i , b_{i}b**i ( 1<=a_{i},b_{i}<=n1<=a**i,b**i<=n , a_{i}≠b_{i}a**i�=b**i ) — the edges of the tree.

    The next line contains a number qq ( 1<=q<=5000001<=q<=500000 ) — the number of operations to perform. Each of the following qq lines contains two space-separated numbers c_{i}c**i ( 1<=c_{i}<=31<=c**i<=3 ), v_{i}v**i ( 1<=v_{i}<=n1<=v**i<=n ), where c_{i}c**i is the operation type (according to the numbering given in the statement), and v_{i}v**i is the vertex on which the operation is performed.

    It is guaranteed that the given graph is a tree.

    输出格式

    For each type 3 operation print 1 on a separate line if the vertex is full, and 0 if the vertex is empty. Print the answers to queries in the order in which the queries are given in the input.

    题意翻译

    • 给出一棵以 11 为根节点的 nn 个节点的有根树。每个点有一个权值,初始为 00。

    • mm

      次操作。操作有

      33

      种:

      1. 将点 uu 和其子树上的所有节点的权值改为 11。
      2. 将点 uu 到 11 的路径上的所有节点的权值改为 00。
      3. 询问点 uu 的权值。
    • 1le n,mle 5 imes 10^51≤n,m≤5×105。


    题解:

    树剖架线段树。

    线段树要维护的操作是区间覆盖和区间清空。

    题解一堆珂朵莉树?

    不明白这种一点都不严肃的算法名称是哪个谁起的。

    反正我用的是树剖架线段树

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn=1e6+7;
    struct node{
    	int l,r,sum,lazy;
    }tree[maxn<<2];
    int head[maxn],nxt[maxn<<1],to[maxn<<1],tot;
    int n,m,x,y;
    void add(int x,int y)
    {
    	nxt[++tot]=head[x];
    	to[tot]=y;
    	head[x]=tot;
    }
    int fa[maxn],deep[maxn],id[maxn],val[maxn],size[maxn],son[maxn],top[maxn],cnt;
    void dfs1(int x,int f)
    {
    	fa[x]=f;
    	size[x]=1;
    	deep[x]=deep[f]+1;
    	int maxson=-1;
    	for(int i=head[x];i;i=nxt[i])
    	{
    		int y=to[i];
    		if(y==f) 
    			continue;
    		dfs1(y,x);
    		size[x]+=size[y];
    		if(size[y]>maxson)
    		{
    			maxson=size[y];
    			son[x]=y;
    		}
    	}
    }
    void dfs2(int x,int t)
    {
    	top[x]=t;
    	id[x]=++cnt;
    	if(!son[x]) 
    		return;
    	dfs2(son[x],t);
    	for(int i=head[x];i;i=nxt[i])
    	{
    		int y=to[i];
    		if(y==son[x]||y==fa[x]) 
    			continue;
    		dfs2(y,y);
    	}
    }
    void build(int pos,int l,int r)
    {
    	tree[pos].l=l,tree[pos].r=r,tree[pos].lazy=-1;
    	if(l==r) 
    		return;
    	int mid=(l+r)>>1;
    	build(pos<<1,l,mid);
    	build(pos<<1|1,mid+1,r);
    }
    void pushdown(int pos)
    {
    	if(tree[pos].lazy!=-1)
    	{
    		tree[pos<<1].sum=(tree[pos<<1].r-tree[pos<<1].l+1)*tree[pos].lazy;
    		tree[pos<<1|1].sum=(tree[pos<<1|1].r-tree[pos<<1|1].l+1)*tree[pos].lazy;
    		tree[pos<<1].lazy=tree[pos].lazy;
    		tree[pos<<1|1].lazy=tree[pos].lazy;
    		tree[pos].lazy=-1;
    	}
    }
    void update(int pos,int l,int r,int y)
    {
    	if(tree[pos].l>=l&&tree[pos].r<=r)
    	{
    		tree[pos].sum=(tree[pos].r-tree[pos].l+1)*y;
    		tree[pos].lazy=y;
    		return;
    	}
    	pushdown(pos);
    	int mid=(tree[pos].l+tree[pos].r)>>1;
    	if(l<=mid) 
    		update(pos<<1,l,r,y);
    	if(r>mid) 
    		update(pos<<1|1,l,r,y);
    	tree[pos].sum=tree[pos<<1].sum+tree[pos<<1|1].sum;
    }
    int query(int pos,int l,int r)
    {
    	if(tree[pos].l>=l&&tree[pos].r<=r) 
    		return tree[pos].sum;
    	pushdown(pos);
    	int mid=(tree[pos].l+tree[pos].r)>>1;
    	int val=0;
    	if(l<=mid) 
    		val+=query(pos<<1,l,r);
    	if(r>mid) 
    		val+=query(pos<<1|1,l,r);
    	return val; 
    }
    void upd_chain(int x,int y,int k)
    {
    	while(top[x]!=top[y])
    	{
    		if(deep[top[x]]<deep[top[y]]) 
    			swap(x,y);
    		update(1,id[top[x]],id[x],k);
    		x=fa[top[x]];
    	}
    	if(deep[x]<deep[y]) 
    		swap(x,y);
    	update(1,id[y],id[x],k);
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<n;i++)
    	{
    		scanf("%d%d",&x,&y);
    		add(x,y);
    		add(y,x);
    	}
    	dfs1(1,0);
    	dfs2(1,1);
    	build(1,1,n);
    	scanf("%d",&m);
    	int opt,x;
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&opt,&x);
    		if(opt==1) 
    			update(1,id[x],id[x]+size[x]-1,1); 
    		else if(opt==2) 
    			upd_chain(x,1,0);
    		else 
    			printf("%d
    ",query(1,id[x],id[x]));
    	}
    	return 0;
    }
    
  • 相关阅读:
    欢天喜地七仙女——Alpha冲刺(11.30)第六天
    欢天喜地七仙女——Alpha冲刺(11.29)第五天
    欢天喜地七仙女——Alpha冲刺(11.28)第四天
    欢天喜地七仙女——Alpha冲刺(11.27)第三天
    欢天喜地七仙女——Alpha冲刺(11.26)第二次
    欢天喜地七仙女——Alpha冲刺(11.25)第一天
    fist-总结随笔
    fist-第十天随笔
    fist-第九天冲刺随笔
    fist-第八天冲刺随笔
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13865721.html
Copyright © 2020-2023  润新知