[Apio2012] 디스패치 (파견) - 트리 세그먼트 병합

얼굴 질문

  Bzoj2809

결심

  욕심이 전략에 따르면 우리는 각 노드가 아들의 트리 라인 통합의 모든 범위 트리 라인, 트리 라인의 아버지와 다음 단일 지점을 구축 할 수 있습니다에 대해 사람들이 다음, 적은 비용을 선택합니다, 그래서 많은 사람들을 선택합니다 에서 수정, 그래서 당신은 신속하게 요구 사항, 수와 트리 라인을 유지하고, 계정으로 범위를 복용의 비용을 충족하기 위해 얼마나 많은 수를 확인하실 수 있습니다 각 노드가 통신이 있기 때문에 숫자는 1E5 동안, 우리는 이산 고려 1E9이 트리 라인은, 그래서 우리는 공간을 압축하는 동적 지점을 열었다. 문제는 노드 수는없는 아들이 남아 있지 Y 경우, 우리는 Y가 X의 아들이 떠난 경우 다음 재귀 아래, 그의 아들에 대한 간주되었다 노드의 X 번호로 통합 노드 수를 설정하려면, 트리 라인을 병합하는 방법입니다 이 L에 도달하면 복귀 또는 == R은 합병 정보는, X 및 Y는 아들이 남아 있지 않은 경우, 좌측 아들 Y이어서 직접 X, 반품 왼쪽 아들 노드 번호 할당. 작업의 오른쪽 아들은 동일합니다.

  하지 권리 아들, 부모 노드에 대한 정보를 그의 아들이 m보다 더 큰되었습니다 합을 떠난 경우, 트리 라인을 결합하고, 업데이트 할 때 작은 최적화도 있습니다, 정말 빠르게처럼 직접 돌아왔다.

  코드의 세부 사항의 나머지 부분을 참조하십시오.

 코드 :

 

#INCLUDE <비트 / stdc ++ H.>
 사용  스페이스 성병; 
타입 정의  LL;
CONST의  INT의 maxn = 100005 ; 

서식 < 클래스 T> 공극 리드 (T & 재) 
{  = 0 ; 
    T 기호 = 1 ;
    문자 의 tmp;
    반면 ((TMP = getchar가 ()) && (TMP < ' 0 ' || TMP> ' 9 ' )) 의 경우 (TMP == ' - ' ) 기호 = - 1; 
    다시 = tmp- ' 0 ' ;
    반면 ((TMP = getchar가 ()) && (TMP> = ' 0 ' && TMP <= ' 9 ' )) = 재 (재 << 3 ) + (Re는 << 1 ) + (tmp- ' 0 ' ); 
    다시 * = 기호; 
} 

INT의 TOT 루트 [maxn, N, m, w [maxn, V [maxn, MAS, AW [maxn, CNT [maxn] F; 
; ANS LL 

구조체 seg_tree {
     INT의 LS, RS, NUM; 
    LL 합계; 
} TR [maxn * 20 ]; 

무효 업데이트 ( INTX) 
{ 
    TR [X] .num = TR [TR [X] .ls] .num + TR [TR [X] .RS] .num; 
    TR [X] .sum = TR [TR [X] .ls] .sum + TR [TR [X] .RS] .sum; 
} 

공극 병합 ( INT (X), INT의 Y, INT의 L, INT의 R) 
{ 
    경우 (Y!의)     복귀 ;
    경우 (L == R) 
    { 
        TR [X] .num + = TR [Y] .num; 
        TR [X] .sum + = TR [Y] .sum;
        반환 ; 
    } 
    INT 중간 = (L + R) >> 1 ;
    만약(TR [X] .ls) 
        (TR [X] .ls, TR [Y] .ls, L, 미드)를 병합; 
    다른 
        TR [X] .ls = TR [Y] .ls;
    경우 (TR의 [그럴 [X] .ls] .sum> m) 
    { 
        업데이트 (X); 
        반환 ; 
    }     
    경우 (TR [X] .RS) 
        병합 (TR [X] .RS, TR [Y] .RS 중간 + 1 , R);
    다른 
        TR [X]의 .RS = 용 TR [Y] .RS; 
    업데이트 (X); 
} 

공극 수정 ( INT (X), INT 발, INT의 L, INT의 R) 
{ 
    경우 (L의 == R)
    { 
        TR [X] .num ++ ; 
        TR [X] .sum + = AW [발];
        반환 ; 
    } 
    INT 중간 = (L + R) >> 1 ;
    경우 (발 <= MID) 
    { 
        경우 (!의 TR [X] .ls) 
            TR [X] .ls = ++ TOT; 
        (TR [X] .ls, 발, L, 중앙)을 수정; 
    } 
    다른 
    { 
        경우 (!의 TR [X] .RS) 
            TR [X] .RS = ++ TOT; 
        수정 (TR [X] .RS, 브로 미드 + 1 , R); 
    } 
    업데이트 (X); 
} 

int로 (쿼리INT의 X, INT의 L, INT의 R은) 나머지 버리는 
{ 
    경우 (나머지> = TR [X] .sum)
         복귀 TR을 [X] .num;
    경우 (L == R)
         복귀 나머지 / AW [L];
    INT 중간 = (L + R) >> 1 , RET = 0 ;
    경우 (TR [X] .ls && 나머지 <= TR [TR [X] .ls] .sum) 
        RET + = 쿼리 (TR [X] .ls, L, 중간, 나머지);
    다른  경우 (TR [X]를 .RS) 
    { 
        RET + = TR [TR [X] .ls] .num; 
        RET+ = 쿼리 (TR [X] .RS 중간 + 1 , R, 나머지 - TR [TR [X] .ls] .sum); 
    }     
    반환 RET를; 
} 

INT 의 main () 
{ 
    (n)이 판독 (m) 판독; 
    위한 ( int로 I = 1 ; i가 <= N; ++ I) 
    { 
        루트 [내가] = ++ TOT;
        INT의 X, Y, Z; 
        (z) 판독 (x)를 읽고, 읽은 (Y)를; 
        F [I]는 =의 X; 
        AW [I] = [I]가 w = Y; 
        V [I] = (Z); 
    } 
    정렬 (AW + 1 , N + AW + 1); 
    CNT ;= 고유 (AW + 1 , AW + N + 1 ) - 아 - 1 ;
    위한 ( int로 I = N, I - I) 
    { 
        수정 (루트 [I] LOWER_BOUND (AW + 1 , AW + CNT + 1 , w [I]) - 아, 1 , CNT); 
        ANS = 최대 (ANS, 1LL에서의 V * [I] * 쿼리 (루트 [I], (1) , CNT (LL) m));
        경우 ([I] F) 
            (루트 [F [I], 루트 [i]를 병합 , CNT)를; 
    } 
    의 printf ( " %의 LLD " , ANS);
    반환  0 
}
코드보기

 

추천

출처www.cnblogs.com/Joker-Yza/p/11235656.html