zoukankan      html  css  js  c++  java
  • [每日一题]: poj 3321 Apple Tree

    题目:

    考察点:

    DFS序、线段树、树状数组、区间操作的数据结构
    

    DFS序不了解的戳这里:

    https://www.cnblogs.com/prjruckyone/p/12754936.html

    线段树不了解的戳这里:

    https://www.cnblogs.com/prjruckyone/p/12293330.html

    侃侃:

    题目中有两种操作:
    1、如果说原来某个节点有苹果,那么就吃掉它,如果这个节点没有苹果,就种上一个。
    2、查询一下以当前节点为根节点的树有多少个苹果(子节点的数量)
    
    那么怎么做呢?
    说到统计子节点的数量,你可能会想到并查集,合并到一起计算一下子节点的数量,但是这里
    还有一个操作 1 ,说明这是一个动态的问题。知道了这一点后,那么我们想一下,支持动态
    修改的数据结构有哪些呢?
    线段树、树状数组、分块大法,and so on.......
    (原谅我的菜,了解这么多)
    如果你熟悉 DFS 序的话,就会很清楚的知道 DFS 序路径中重复走到一个点时正好可以
    代表一棵子树(详情请点击上方 DFS 序的链接)
    不熟悉的话正好学习一下(嘻嘻)
    这时候我们就可以将每个子树都表示成在 DFS 序中的一个区间,如果我们求子树的大小
    实际上就是求区间和,吃掉或者种苹果实际上就是单点修改。
    到这里就比较明了了。
    

    Code:

    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 1e5 + 10;
    
    struct node {
    	int l,r,sum;
    } tr[maxn << 2];
    
    int head[maxn << 1],Next[maxn << 1],ver[maxn << 1];
    
    int w[maxn],st[maxn],ed[maxn];
    
    int tot,idx,n,u,v,m,t;
    
    void add(int u,int v) {
    	ver[++ tot] = v,Next[tot] = head[u],head[u] = tot;
    	return ;
    }
    
    // st[]: 记录起点 ed[]: 记录终点,两者组合成一个子树的区间
    // st 和 ed 都是存储的 DFS 序 
    void DFS(int u,int fa) {
    	st[u] = ++ idx;
    	for(int i = head[u]; i ; i = Next[i]) {
    		int y = ver[i];
    		if(y != fa) {      // 由于是树,所以走过的点不能再走,也可以用标记数组进行标记一下
    			DFS(y,u);  // 根据深度优先搜索,递归到最深处再回溯
    		}
    	}
    	ed[u] = idx;
    	return ;
    }
    
    void pushup(int u) {
    	tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
    	return ;
    }
    
    void build(int u,int l,int r) {
    	tr[u].l = l,tr[u].r = r;
    	if(l == r) {
    		tr[u].sum = w[r];
    		return ;
    	}
    	int mid = l + r >> 1;
    	build(u << 1,l,mid);
    	build(u << 1 | 1,mid + 1,r);
    	pushup(u);
    	return ;
    }
    
    // 更新方式 1 
    void update1(int u,int x,int v) {
    	if(tr[u].l == tr[u].r) {
    		tr[u].sum += v;
    		w[x] += v;
    		return ;
    	}
    	int mid = tr[u].l + tr[u].r >> 1;
    	if(x <= mid) update(u << 1,x,v);
    	else update(u << 1 | 1,x,v);
    	pushup(u);
    	return ;
    }
    
    // 更新方式 2 
    void update2(int u,int x) {
    		if(tr[u].l == tr[u].r) {
    		tr[u].sum ^= 1;
    		return ;
    	}
    	int mid = tr[u].l + tr[u].r >> 1;
    	if(x <= mid) update(u << 1,x,v);
    	else update(u << 1 | 1,x,v);
    	pushup(u);
    	return ;
    } 
    
    int query(int u,int L,int R) {
    	if(L <= tr[u].l && tr[u].r <= R) {
    		return tr[u].sum;
    	}
    	int sum = 0;
    	int mid = tr[u].l + tr[u].r >> 1;
    	if(L <= mid) sum = query(u << 1,L,R);
    	if(R > mid) sum += query(u << 1 | 1,L,R);
    	return sum;
    }
    
    int main(void) {
    	scanf("%d",&n);
    	for(int i = 1; i < n; i ++) {
    		scanf("%d%d",&u,&v);
    		add(u,v);
    		add(v,u);
    		w[i] = 1;                // 初始化数组,刚开始每个节点上都有一个苹果
    	}
    	w[n] = 1;
    	DFS(1,-1);
    	build(1,1,idx);  							// 在 DFS 序的基础上建立一颗线段树 
    	scanf("%d",&m);
    	while(m --) {
    		char op;
    		int x;
    		cin >> op >> x;
    		// 单点修改 
    		if(op == 'C') {
    			// st 是 DFS 序 (-1 标记为吃掉了这个苹果)
                            // 我们线段树修改的是 DFS 序, w[]数组是原序列
    			if(w[st[x]]) update1(1,st[x],-1);
    			else update1(1,st[x],1);
    			
    			//update2(1,st[x]);
    		} else {
    		// 区间查询 
    			printf("%d
    ",query(1,st[x],ed[x]));
    		}
    	}
    	return 0;
    }
    

    后记:

    感谢师傅大佬的倾囊而助,帮我找到一个调了很久的 bug。
    另外,线段树我们会,DFS序也了解,和在一起怎么就搞不
    出来了呢?
    还是得多练习一下综合性的题目。
    如有解释的不到位的地方,或者哪里有问题的地方,欢迎    
    各位大佬指出,在此万分感谢。
  • 相关阅读:
    浅谈Slick(2)- Slick101:第一个动手尝试的项目
    浅谈Slick(1)- 基本功能描述
    Cats(4)- 叠加Free程序运算结果,Stacking monadic result types
    Cats(3)- freeK-Free编程更轻松,Free programming with freeK
    Cats(2)- Free语法组合,Coproduct-ADT composition
    Cats(1)- 从Free开始,Free cats
    Scalaz(59)- scalaz-stream: fs2-程序并行运算,fs2 running effects in parallel
    Scalaz(58)- scalaz-stream: fs2-并行运算示范,fs2 parallel processing
    Scalaz(57)- scalaz-stream: fs2-多线程编程,fs2 concurrency
    Scalaz(56)- scalaz-stream: fs2-安全运算,fs2 resource safety
  • 原文地址:https://www.cnblogs.com/prjruckyone/p/12755361.html
Copyright © 2011-2022 走看看