このアイデアは非常に興味深いです -
ツリー・チェーンを使用して一度だけ各色の寄与を確認し、その後、持続セグメント・ツリーのメンテナンスであること
コード:
#include <セット> の#include <cstdioを> する#include <CStringの> する#include <アルゴリズム> の#define N 100005 の#define setIO(S)freopenは(S ".IN"、 "R"、標準入力)、(S freopenは」。アウト」、 『』ワット、STDOUT) 名前空間stdを使用。 名前空間SEG { に#define LSON T [X] .ls の#define rson T [X] .RS INT TOT。 構造体ノード { int型LS、RS、合計。 } T [N * 80]。 ボイドCLR() { 用(INT iは= 1; I <= TOT; ++ I)T [i]は.ls = T [i]を.RS = T [i]が.SUM = 0。 TOT = 0; } INT newnode() { リターン++ TOT。 ボイドビルド(INT&X、INT L、int型R) { X = newnode()。 (L == R)戻った場合。 INTミッド=(L + R)>> 1。 ビルド(LSON、L、ミッド)(L <= MID)の場合。 IF(R> MID)ビルド(rson、ミッド+ 1、R)。 } int型のCOP(int型のx、int型のL、R INT、INT P、INT V) { int型今= newnode()。 T [今] = T [X]。 T [今] .SUM + = V。 (L == R)は今戻った場合。 INTミッド=(L + R)>> 1。 IF(p <= MID)T [今] .ls = COP(LSON、L、中、P、V)。 他T [今] .RS = COP(rson、ミッド+ 1、R、P、V)。 今すぐ返します。 } INTクエリ(int型のx、int型、L、R INT、INT L、int型R) { (!X)であれば0を返します。 IF(L> = L && R <= R)戻りT [X] .SUM。 int型の再= 0; INTミッド=(L + R)>> 1。 (L <= MID)再+ =クエリ(LSON、L、中、L、R)であれば、 IF(R> MID)再+ =クエリ(rson、ミッド+ 1、R、L、R)。 再を返します。 } の#undef LSON の#undef rson }。 セット<整数> SE [N]。 セット<整数> ::イテレータFR、BA; INTエッジ、N、M、ティム、CT。 INT HDに[N]、[N]、NEX [N]、COL [N]、NOD [N]、ST [N]、ED [N]。 FA INT [N]、DFN [N]、DEP [N]、サイズ[N]、息子[N]、トップ[N]。 INT ID [N]、RT [N]。 ブールCMP(int型B、INT) { 戻りDEP [A] <DEP [B]。 } ボイド追加(INT U、V INT) { NEX [++エッジ] = HD [U]、[エッジ] = VにHD [U] =エッジ; } ボイドDFS1(INT U、INT FF) { サイズ[U] = 1。 DFN [U] = ++ティム。 ST [U] = DFN [U]。 NOD [DFN [U] = U。 DEP [U] = DEP [FF] +1。 (; iはNEX [I] = [U] INT I = HD)用 { int型V =に[I]を、 DFS1(V、U); サイズ[U] + =サイズ[V]。 IF(サイズ[V]>サイズ[息子[U])息子[U] = V。 } ED [U] =ティム。 } ボイドDFS2(INT U、INT TP) { トップ[U] = TP。 IF(息子[U])DFS2(息子[U]、TP)。 (; iはNEX [I]を= [U] INT I = HD)用 { IF(の[I] =息子[U]!) { DFS2([I]に、[I]に); } } } int型LCA(int型のx、int型のY) { 一方(上面[X]!= TOP [Y]) { DEP [トップ[X]]> DEP [トップ[Y]]?X = FA [トップ[X ] Y = FA [トップ[Y]。 } 戻りDEP [X] <DEP [Y] X:Y;? } ボイド解く() { = 0最後INT I、J、。 scanf関数( "%D%D"、&N、&M)。 ための式(I = 1; I <= N; ++ I)のscanf( "%d個"、&COL [I])。 以下のために(I 2 =、iが<= N; ++ I) { scanf関数( "%d個"、&FA [I])。 追加(FA [i]は、I)。 } DFS1(1,0)。 DFS2(1,1)。 ため(I 1 =、iが<= N; ++ I)のID [I] = I。 ソート(ID + 1、ID + 1 + N、CMP)。 int型LST = 0; SEG ::ビルド(RT [0]、1、N) (++ I; I <= n iは= 1)のための { INT P = ID [i]は、 INT C = COL [P]。 一方、(DEP [P]> LST)RT [LST + 1] = RT [LST] ++ LST。 SE [C] .insert(DFN [P])。 FR = BA = SE [C] .lower_bound(DFN [P])、BA ++。 IF(FR = SE [C] .begin()!) { --fr。 RT [LST] = SEG :: COP(RT [LST]、1、nは、DFN [LCA(NOD [* FR]、P)] - 1)。 ++ FR; } IF(BA!= SE [C] .END()) { RT [LST] = SEG :: COP(RT [LST]、1、nは、DFN [LCA(NOD [* BA]、P)] - 1)。 } (FR = SE [C] .begin()&& BA = SE [C] .END()!)であれば { --fr。 RT [LST] = SEG :: COP(RT [LST]、1、nは、DFN [LCA(NOD [* FR]、NOD [* BA)]、1)。 } RT [LST] = SEG :: COP(RT [LST]、1、nは、DFN [P]、1)。 } (iは= 1; I <= M; ++ i)に対する { int型のx、D。 scanf関数( "%D%D"、およびX、&D)。 X ^ =最後、D ^ =最後。 最後= SEG ::クエリ(RT [分(N、DEP [X] + D)]、1、nは、ST [x]は、ED [X])。 printf( "%d個\ n"は、最後の); } (iは= 1; I <= N; ++ i)に対する息子[I] = 0; (iは= 1; I <= N; ++ i)に対するHD [I] = 0; ための式(I = 1; I <=縁; ++ I)NEX [I] =に[I] = 0; エッジ=ティム= 0。 ワンセグ:: CLR(); SE [I] .clear()(iは++; <I = N I = 1の)のため; } int型のmain() { // setIO( "入力")。 I、J、Tをint型。 scanf関数( "%のD"、&T)。 一方、(T--)(解きます)。 0を返します。 }