当时比赛的时候,队友一读完题就叫我看这道,目测就是数据结构。
当时我看了下题,YY了下算法,以为直接从当前点一直往上搜,找到根节点就可以了,因为我突然SB了一下,最近做平衡树的题目做多了,脑子里一下子就想到树的高度是logN的 。然后YY了一下MlogN肯定能过。。。
然后TLE就开始了,后来突然发现这又不是二叉搜索树,极端数据肯定有高度为N/2的。那我就SB了。
真是审题太不仔细了,其实想想也能想到,半天都没人做这道题,怎么可能这么水,也怪当时我脑子抽到了。
还好及时换题了。当时比赛的时候没搞出来,赛后看了标程一知半解的,还好神牛在DISCUSS里面指点了一下。
总算是写出来了。
题意:
给你一棵二叉树,每个节点上都有一个值。
然后对于每次询问,对于一个球 (pos , weight),球的目标是到达pos ,球的重量为weight ,球从根节点开始往下走。
如果当前节点的值大于球的重量,那么往两边走的概率都是1/2。
如果当前节点的值小于球的重量,那么球往左边走的概率是1/8,右边走的概率是7/8。
如果两者相等,那么球就会停在该节点上。
最后输出从根节点到pos的概率,用(7 ^ x) / ( 2 ^ y) 表示,最后输出x , y 即可。
思路:
dfs+树状数组。
首先,我们对树的节点的值和球的重量进行离散化,这里就不多赘述了。
这里我们要维护两个树状数组,分别存所有的左子树,和右子树,用TL[] 和 TR[] 来表示 。
对于每次dfs到的点,先查询这个点上的询问,记录下四个值。LS,LB,RS,RB,分别代表左子树小于当前值的节点数,左子树大于当前值的节点数,右子树小于当前值的节点数,右子树大于当前值的节点树。
因为我们很容易得到(7 ^ x)的值一定是往右子树上走并且当前节点值小于球的重量,所以x的值就等于RS的值。
同理(2 ^ y) , y的值就是(LB + RB + 3 *(LS + RS) )。
所以,每次询问的时候,我们只要记录下这四个值就可以了。
用树状数组就可以在logN的时间内求出这些值。
当dfs到这个点时,我们将这个点插入到树状数组,即在这个点的位置add(1),因为所有的数据已经离散化了,所以可以算出N最大为20W。
讲的太烂了,代码如下。。
#include <iostream> #include <cstdio> #include <algorithm> #include <string> #include <cmath> #include <cstring> #include <queue> #include <set> #include <vector> #include <stack> #include <map> #include <iomanip> #define PI acos(-1.0) #define Max 2505 #define inf 1<<28 #define LL(x) ( x << 1 ) #define RR(x) ( x << 1 | 1 ) #define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i ) #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define mp(a,b) make_pair(a,b) #define PII pair<int,int> using namespace std; /***输入优化***/ inline void RD(int &ret) { char c; do { c = getchar(); } while(c < '0' || c > '9') ; ret = c - '0'; while((c=getchar()) >= '0' && c <= '9') ret = ret * 10 + ( c - '0' ); } /***变量声明***/ struct kdq { int e , id ,next ; } ed[1111111] ; int head[111111] ,num = 0 ; int Ls[211111] ,Lb[211111] ,Rs[211111] ,Rb[211111] ; int val[111111] ; int qe[211111] ;//离散化用 vector<int>query[111111] ; int TL[111111] , TR[111111] ;//树状数组 bool vis[111111] ; int askpos[111111] ,askweight[111111] ; int hash[111111] ; int hash1[111111] ; int isE[111111] ; int n ; /***初始化***/ void init() { mem(Ls , 0) ; mem(Lb , 0) ; mem(Rs , 0) ; mem(Rb , 0) ; mem(head , -1) ; mem(TL , 0) ; mem(TR , 0) ; mem(isE , 0) ; mem(vis , 0) ; num = 0 ; } void add(int s ,int e ,int id) { ed[num].e = e ; ed[num].id = id ; ed[num].next = head[s] ; head[s] = num ++ ; } /***树状数组***/ int lowbit(int x) { return x & (-x) ; } void add(int c[] ,int x ,int num) { for (int i = x ; i <= n ; i += lowbit(i)) { c[i] += num ; } } int sum(int c[] ,int x ) { int ans = 0 ; for (int i = x ; i > 0 ; i -= lowbit(i)) { ans += c[i] ; } return ans ; } /***dfs***/ void dfs(int id) { /***询问***/ for (__typeof(query[id].begin()) i = query[id].begin() ; i != query[id].end() ; i ++ ) { int tt = hash1[*i] ; //cout << *i << endl; Ls[*i] = sum(TL ,tt - 1) ;//左子树的前tt - 1项和,即节点值小于val[askpos[*i]]的节点总数。 Lb[*i] = sum(TL ,n) - sum(TL , tt) ;//节点值大于val[askpos[*i]]的节点总数。 Rs[*i] = sum(TR , tt - 1) ;//同理 Rb[*i] = sum(TR , n) - sum(TR , tt ) ;//同理 //cout << Ls[*i] << " " << Lb[*i] << " " << Rs[*i] << " " << Rb[*i] << endl; if(vis[tt]) { isE[*i] = 1 ; } } for (int i = head[id] ; ~i ; i = ed[i].next) { int e = ed[i].e ; int tt = hash[id] ; int flag = ed[i].id ; if(flag == 1) {//如果是左子树 add(TL , tt , 1) ;//在TL的tt位置加上1,TL是左子树的树状数组。 } else { add(TR , tt , 1) ;//同理 } vis[tt] = 1 ; dfs(e) ; if(flag == 1) { add(TL , tt, -1 ) ; } else { add(TR , tt , -1) ; } vis[tt] = 0 ; } } /***debug***/ void debughash(int nn ,int pos) { if(pos == 0) { for (int i = 1 ; i < nn ; i ++ ) { cout << hash[i] << " " ; } cout << endl; } else if(pos == 1) { for (int i = 1 ; i < nn ; i ++ ) { cout << hash1[i] << " " ; } cout << endl; } } int main() { int T ; cin >> T ; while ( T -- ) { int nn ; init() ; cin >> nn ; int cnt = 0 ; int cnt1 = 1 ; int cnt2 = 1 ; for (int i = 1 ; i <= nn ; i ++ ) { RD(val[i]) ; qe[cnt ++ ] = val[i] ; hash[cnt1 ++ ] = val[i] ; } int m ; cin >> m ; /***建树***/ while(m -- ) { int a , b , c ; RD(a) ; RD(b) ; RD(c) ; add(a , b , 1) ;//左子树 add(a , c , 0) ;//右子树 } /***询问***/ cin >> m ; for (int i = 1 ; i <= nn ;i ++ ){ query[i].clear() ; } for (int i = 1 ; i <= m ; i ++ ) { RD(askpos[i]) ; RD(askweight[i]) ; query[askpos[i]].push_back(i) ; qe[cnt ++ ] = askweight[i] ; hash1[cnt2 ++ ] = askweight[i] ; } /***离散化***/ sort(qe , qe + cnt) ; n = unique(qe , qe + cnt ) - qe ; for (int i = 1 ; i < cnt1 ; i ++ ) { hash[i] = lower_bound(qe, qe + n , hash[i]) - qe + 1 ; } for (int i = 1 ; i < cnt2 ; i ++ ) { hash1[i] = lower_bound(qe , qe + n ,hash1[i]) - qe + 1 ; } dfs(1) ; for (int i = 1 ; i <= m ; i ++ ) { if(isE[i]) { puts("0") ; } else { int a = 3 * Ls[i] + 3 * Rs[i] + Lb[i] + Rb[i] ; int b = Rs[i] ; printf("%d %d\n", b , a ) ; } } } return 0 ; }