zoukankan      html  css  js  c++  java
  • HDU4836 The Query on the Tree(树状数组&&LCA)

    由于智力的问题,百度之星完全lu不动。。开场看第一题根据题目给的条件我觉得一定是可以构造出来的,题目给的意思颇有鸽巢原理的感觉,于是觉得开场第一题应该就是智力构造题了,想了半个小时,发现完全想不动,于是只能放弃了去想后面的题。

    然后看第二题的数据结构,树上的询问,支持点修改,询问子树和,还有换根,然后心里想,我擦,这不是LCT么,但是我没学呀,然后细心的翻出之前打印的论文研读了很久,发现普通的LCT只能解决询问树路径上的东西,然后看论文上写如果支持子树操作的话就需要Euler-tour-tree什么的,想了一个多小时都想不到怎么用LCT,最后只能作罢。

    然后看了三四题觉得也没什么思路,就去看第五题了,我感觉第五题是有思路的,对两个串建自动机,然后dp[i]定义为状态i的胜率,那么每个状态有两个转移边,转移到xi以及xj状态,那么dp[i]=1/2(dp[xi]+dp[xj]),然后边界就是我方胜利的状态为1,敌方胜利的状态为0,然后我希望能够通过发现图里深层的关系以期避免高斯消元,但是怎么搞都觉得是要高斯消元的,但是因为题目输出的是最简分数,分数版本的高斯消元我感觉我是写不粗来的,然后就只能作罢了。赛后听英姐说用LCM去消,我就明白了其实就是消元的时候按照高中学的那种消去法就好了,不要搞什么小数出来,有空写写看下能不能过。。

    最后只能回头去看最多人过的第二题了,在纸上画了一下发现规律了,将原来的树保持不变,修改的时候按照传统的树状数组的点更段询就可以了,关键是在询问的时候,如果当前 询问的点是当前根的父亲,那么答案应该是 所有权值的和-(询问点包含根的那棵子树的和),否则就直接询问就可以了。要写一个LCA来求出询问点到根的路径的下一个点,然后每次询问都是logn的。

    好久没写代码了呢,回头搜下看下第一题是怎么作粗来的。。

    #pragma warning(disable:4996)
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    
    #define maxn 10050
    #define maxlogv 16
    int bit[maxn];
    int n;
    
    void add(int x, int v)
    {
    	while (x <= n){
    		bit[x] += v;
    		x += x&(-x);
    	}
    }
    
    int query(int x)
    {
    	int ret = 0;
    	while (x > 0){
    		ret += bit[x];
    		x -= x&(-x);
    	}
    	return ret;
    }
    
    
    int first[maxn];
    int nxt[2 * maxn];
    int vv[2 * maxn];
    int e;
    void addEdge(int u, int v)
    {
    	vv[e] = v; nxt[e] = first[u];
    	first[u] = e++;
    }
    
    
    int pre[maxn];
    int post[maxn];
    vector<int> G[maxn];
    int val[maxn];
    int dfs_clock;
    int p[maxn][maxlogv];
    int dep[maxn];
    
    
    void dfs(int u,int fa,int d)
    {
    	p[u][0] = fa; dep[u] = d;
    	pre[u] = ++dfs_clock; int v;
    	for (int i = first[u]; i !=-1; i=nxt[i]){
    		v = vv[i];
    		if (!pre[v]) dfs(v,u,d+1);
    	}
    	post[u] = dfs_clock;
    }
    
    void setRoot(int root)
    {
    	memset(pre, 0, sizeof(pre));
    	memset(post, 0, sizeof(post));
    	memset(p, -1, sizeof(p));
    	memset(dep, 0, sizeof(dep));
    	dfs_clock = 0;
    	dfs(root,-1,0);
    	memset(bit, 0, sizeof(bit));
    	for (int i = 1; i <= n; i++){
    		add(pre[i], val[i]);
    	}
    }
    
    void getp()
    {
    	for (int j = 0; j + 1 <= maxlogv; j++){
    		for (int i = 1; i <= n; i++){
    			if (p[i][j] != -1){
    				p[i][j + 1] = p[p[i][j]][j];
    			}
    		}
    	}
    }
    
    bool isFather(int u, int v)
    {
    	return pre[u] <= pre[v] && pre[v] <= post[u];
    }
    
    int findPostFather(int u, int v)
    {
    	int gap = dep[v] - dep[u];
    	gap -= 1;
    	for (int i = maxlogv; i >= 0; i--){
    		if ((gap >> i) & 1){
    			v = p[v][i];
    		}
    	}
    	return v;
    }
    
    int main()
    {
    	int T; cin >> T; int ca = 0;
    	while (T--)
    	{
    		scanf("%d", &n);
    		int ui, vi;
    		memset(first, -1, sizeof(first)); e = 0;
    		for (int i = 0; i < n - 1; i++){
    			scanf("%d%d", &ui, &vi);
    			addEdge(ui, vi);
    			addEdge(vi, ui);
    		}
    		int tot = 0;
    		for (int i = 1; i <= n; i++){
    			scanf("%d", val + i);
    			tot += val[i];
    		}
    		setRoot(1);
    		int root = 1;
    		getp();
    		int m; scanf("%d", &m);
    		char s[12];
    		printf("Case #%d:
    ", ++ca);
    		for (int i = 0; i < m; i++){
    			scanf("%s",s);
    			if (s[0] == 'Q'){
    				scanf("%d", &ui);
    				if (ui == root) {
    					printf("%d
    ", tot); continue;
    				}
    				if (isFather(ui, root)){
    					vi = findPostFather(ui,root);
    					printf("%d
    ", tot - (query(post[vi]) - query(pre[vi] - 1)));
    				}
    				else{
    					printf("%d
    ", query(post[ui]) - query(pre[ui] - 1));
    				}
    			}
    			else if (s[0] == 'C'){
    				scanf("%d%d", &ui, &vi);
    				add(pre[ui], vi - val[ui]);
    				tot += vi - val[ui];
    				val[ui] = vi;
    			}
    			else{
    				scanf("%d", &ui);
    				root = ui;
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    免费使用Adobe Flash Builder 4.6方法
    MySQL中concat函数
    PHP漏洞全解
    discuz 论坛 解决投票后不返回,提示AJAX错误的折中解决办法 common.js错误
    CoreSeek快速安装
    JSP基本语法
    『JAVA基础』使用JavaMail发邮件的实例 (转载)
    struts2过滤器和拦截器的区别
    【转】 myeclipse安装svn插件的多种方式
    用Java编写计算器的几种常见的做法
  • 原文地址:https://www.cnblogs.com/chanme/p/3762871.html
Copyright © 2011-2022 走看看