部分文字列の識別] [BZOJ1396

フェイス質問

http://darkbzoj.tk/problem/1396

問題の解決策

#include <cstdioを> 
する#include <iostreamの> 
する#include <CStringの> 
する#include <ベクトル>
 の#define RIレジスタint型
 の#define N 500050
 使用して 名前空間STDを、
ベクター < INT >息子[N << 1 ]。
int型のn;
INTの和[N]、ANS [N]。

構造体Segment_tree {
   INT MINV [N << 2 ]。
  無効クリア(){
     (RI i = 1 ; iは= < 4 * N; iは++)MINV [I] = N。
  } 
  無効プッシュダウン(int型X){
     場合(MINV [X] <MINV [X << 1 ])MINV [X << 1 ] = MINV [X]。
    もし(MINV [X] <MINV [X << 1 | 1 ])MINV [X << 1 | 1 ] = MINV [X]。
  } 
  INTクエリ(int型のx、int型 LB、INT RB、INT LOC){
     場合(LB == RB)戻りMINV [X]。
    プッシュダウン(X)。
    INT半ば=(LB + RB)/ 2 もし(LOC <= MID)戻りクエリ(X << 1、LB、中間、LOC)。他の リターンクエリ(X << 1 | 1、ミッド+ 1 、RB、LOC)。
  } 
  ボイド変化(int型のx、int型 LB、INT RB、INT L、のint R、int型K){
     場合(R <LB || L> RB)のリターン;
    もし(L <=ポンド&& RB <= R){ 
      MINV [X] = 分(K、MINV [X])。
      返します
    } 
    プッシュダウン(X)。
    INT半ば=(LB + RB)/ 2 
    変更(X << 1、LB、中間、L、R、K)。変化(X << 1 | 1、中間+ 1 、RB、L、R、K)。
  } 
}、T。

構造体SAM {
   int型 FF [N << 1 ]、LEN [N << 1 ]、CNT [N << 1 ]。
  INT CH [N << 1 ] [ 26 ]。
  int型の LOC [N << 1 ]。
  int型ラス、TOTを。
  ボイドのinit(){ 
    ラス = TOT = 1 
  } 
  ボイド(伸びるint型 C、INT LA){
     int型の NP = ++ TOT、P =ラスと、ラス=TOT; 
    LEN [NP] = LEN [P] + 1CNT [NP] = 1LOC [NP] = ラ。
    一方(!P && CH [P] [C])CH [P] [C] = NP、Pの=のFF [P]。
    もし(!p)はFF [NP]は= 1 ;
    {
       INT Q = CH [P]、[C]。
      もし(LEN [Q] == lenの[P] + 1)FF [NP] = Q。
      他の{
         int型 NQ = ++ TOT;
        (RI i = 0 ; iは< 26 ; I ++)CH [NQ] [I] = CH [Q] [I]; FF [NQ] =のFF [Q]。
        LEN [NQ] = LEN [P] + 1 
        FF [NP] = FFの[Q] = NQ。
        一方(P && CH [P] [C] == Q)CH [P] [C] = NQ、P = FF [P]。
      } 
    } 
  } 
  
  ボイドmaketree(){
     (RI i = 1 ; I <= TOT; iが++ )息子[FF [I]一back(I)。
  } 
  ボイド treesum(INT X){
     ため(RI i = 0 ; I <息子[X] .size(); I ++ ){ 
      treesum(息子[X] [I])。
      もし(CNT [息子[X] [I])LOC [X] = LOC [息子[X] [I]]。
      CNT [X] + = CNT [息子[X] [I]]。
    } 
  } 
  ボイドワーク(){
     (RI I = 1 ; I <= TOT; iが++)場合(CNT [I] == 1 ){ 
      t.change(11、nは、LOC [I] -len [FF [I]、LOC [I ]、LEN [FF [I] + 1 )。
      和[LOC [I] -len [FF [I]] - 1 ] ++; 合計[LOC [i]が-len [I]] - 
    } 
  } 
} SAM。
チャーS [N]。

INT メイン(){ 
  sam.init()。
  scanf関数(" %sの" 、S); 
  N = STRLEN(S)。
  (RI i = 0 ; iがn <; iは++ ){ 
    sam.extend(S [I] - ['、私は+ 1 )。
  } 
  sam.maketree()。
  sam.treesum(1 )。
  t.clear(); 
  sam.work(); 
  (RI i = 1 ; iが<= N iが++ ){ 
    ANS [I] = t.query(11 、N、I)。
  } 
  のための(RI I = N; I> = 1 ; i-- ){ 
    和[I] + =和[I + 1 ]。
    もし(SUM [I]> 0 ){ 
      ANS [I] =分(ANS [i]は、ANS [I + 1 ] + 1 )。
    } 
  } 
  のための(RI I =1 ; iが<= N; iが++)のprintf(" %d個の\ n " 、ANS [I])。
}

 

おすすめ

転載: www.cnblogs.com/shxnb666/p/11279321.html