hdu 4605
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4605
题目大意:给你一棵二叉树,每个节点有一个w值,现在有一颗小球,值为x,从根节点往下掉,如果w==x,那么它就会停止;如果w>x,那么它往左、右儿子的概率都是1、2;如果w<x,那么它往左儿子的概率是1/8,右儿子是7/8。现在给你q个询问,问你值为x的球道达节点u的概率为多少。
思路:比赛的时候,我们都是跟着榜走的,都卡在那道Deque上了,根本没有看这题。昨天晚上自己看了一下,其实也没有什么正确的解题思路,暴力谁都会,但是肯定超时,要不然也不会比赛时没几个队伍去做这题了。然后,当然就看题解了喽,看题解先开始就是有一个地方一直不明白,它所说的树状数组(线段树)到底维护的是什么,它的区间又是什么东西。想来想去一直没想明白,去网上看别人的博客,东看西看又找了个同学去问,感觉也还是这几个地方不懂(当然不是他们讲的不好,而是我有个地方卡壳了,对线段树这个工具应用还不熟啊),后来,自己按照他们讲的方向去想了想,终于顿悟了。它不是每次询问都输出,而是先把所有的询问都存起来,遍历的时候一次性弄完,再输出,这个不是重点,关键还是在我上面所说的树状数组那里,对于树状数组来说,每个叶子节点A[ i ]存的是当前dfs 走过的路径上 w为 i 的结点个数,这样dfs下来的时候,每次都做update操作(递归时A[ w ]+1,回溯时再减掉),当当前节点被mark时,就询问。关于x、y的计算方法是这样的:设a为从根节点到当前节点左路径中小于x的节点数,b为从根节点到当前节点左路径中大于x的节点数,c为右路径中小于的,d为右路径中大于的,则 x = c,y = b+d+3*(a +c),这个自己画个图想想,列列式子就明白了。由于dfs到某个节点,对应的树状数组里存的就是这条路径对应的个数,询问的复杂度是O(logn)。多以整个过程在一遍dfs过后就完成了。由于分左、右路径,所以我就开了两个树状数组,一个表示左,一个表示右,那些开一个的其实也一样,都要分左、右的。
话说,这道题之前我只会线段树,树状数组不会,虽然说是一直都想学来着。。 = = ,因为这道题,网上大家写的都是树状数组,我也想看看树状数组到底是什么东西,就去学了。结果发现,这东西果然简单,学学就是5分钟的事情,然后再顺便A道题目。。 它能实现一些简单的求和和更新操作,虽然适用范围比线段树小,但是人家编程复杂度小啊,敲起来快,简单,空间也省。因为这道题只需要求和和单点更新,果断是树状数组啊!
今天早上来了,果断把它A了,可是我这个代码我发现一个神奇的问题,如果我在dfs中处理mark节点时如果sum(x),sum(x-1)这些值先算好保存下来(免得重复算么)再算要求的值,就是RE(爆栈),而直接当场就算,就是AC的。。 神奇啊,不解。。 = =
代码如下:
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
#define MP make_pair
const int MAXN = 111111 ;
struct Node
{
int w,lson,rson;
} node[MAXN];
int mark[MAXN];
vector < pair <int,int> > ques[MAXN];
int ans[MAXN][2];
int tot;
int sum_l[MAXN],sum_r[MAXN];
map <int,int> my_map;
int lowbit(int x)
{
return x&(-x);
}
void update_left(int pos,int x)
{
while(pos<=tot)
{
sum_l[pos]+=x;
pos += lowbit(pos);
}
}
void update_right(int pos,int x)
{
while(pos<=tot)
{
sum_r[pos]+=x;
pos += lowbit(pos);
}
}
int sum_left(int pos)
{
int s=0;
while(pos>=1)
{
s += sum_l[pos];
pos -= lowbit(pos);
}
return s;
}
int sum_right(int pos)
{
int s=0;
while(pos>=1)
{
s += sum_r[pos];
pos -= lowbit(pos);
}
return s;
}
void dfs(int root)
{
if(root==-1) return ;
if(mark[root])
{
for(int i = 0;i<ques[root].size();i++)
{
int x = my_map[ques[root][i].first];
int id = ques[root][i].second;
if(sum_left(x)-sum_left(x-1)>0||sum_right(x)-sum_right(x-1)>0) ans[id][0] = -1;
else
{
ans[id][0] = sum_right(x-1);
ans[id][1] = sum_left(tot)-sum_left(x)+sum_right(tot)-sum_right(x)+3*(sum_left(x-1)+sum_right(x-1));
}
}
}
update_left(my_map[node[root].w],1);
dfs(node[root].lson);
update_left(my_map[node[root].w],-1);
update_right(my_map[node[root].w],1);
dfs(node[root].rson);
update_right(my_map[node[root].w],-1);
}
void init()
{
memset(sum_l,0,sizeof(sum_l));
memset(sum_r,0,sizeof(sum_r));
}
int hash[MAXN];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&node[i].w);
hash[i] = node[i].w;
}
int m;
scanf("%d",&m);
int a,b,c;
for(int i =1;i<=n;i++)
node[i].lson = node[i].rson = -1;
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
node[a].lson = b;
node[a].rson = c;
}
int q;
scanf("%d",&q);
memset(mark,0,sizeof(mark));
for(int i = 1;i<=n;i++)
ques[i].clear();
int u,x;
for(int i = 1;i<=q;i++)
{
scanf("%d%d",&u,&x);
mark[u] =1;
ques[u].push_back(MP(x,i));
hash[n+i] = x;
}
sort(hash+1,hash+1+n+q);
tot = unique(hash+1,hash+1+n+q)-hash-1;
//printf("tot = %d\n",tot);
my_map.clear();
for(int i=1;i<=tot;i++)
my_map[hash[i]] = i;
init();
dfs(1);
for(int i = 1;i<=q;i++)
{
if(ans[i][0]==-1) puts("0");
else printf("%d %d\n",ans[i][0],ans[i][1]);
}
}
return 0;
}