当时比赛的时候,队友一读完题就叫我看这道,目测就是数据结构。
当时我看了下题,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 ;
}