zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    第一次博客作业
    201771010110孔维滢《面向对象程序设计(java)》第二周学习总结
    孔维滢201771010110《面向对象程序设计(java)》第一周学习总结
    2018-2019-1 20165230《信息安全系统设计基础》第二周学习总结
    # 2018-2019-1 20165230 《信息安全系统设计基础》第三周学习总结
    20165230 获奖感想与学习心得
    20165230 2017-2018-2《Java程序设计》课程总结
    20165230 《Java程序设计》实验五《网络编程与安全》实验报告
    20165230 《Java程序设计》实验四 Android程序设计实验报告
    20165230 《Java程序设计》实验三 敏捷开发与XP实践 实验报告
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13865721.html
Copyright © 2011-2022 走看看