【ZJOI2007】非表示と問題解決レポート(ダイナミック点分割統治)を求めます

[ZJOI2007]かくれんぼ

最近、コードの最大量にタイトルを行って(もちろん、私は醜い書き込み....)

問題の意味

\(N- \)ツリーノード(\(\ルN- 5 ^ 10 \) )、各ノードは、黒または白です。

そこ\(M \)の操作(\(M \ル。5 \ ^ 10. 5回\) )、二つの動作があり、

  1. \(x \)カラーリバーサルの。
  2. 右最も遠い木黒ドット間の距離を照会します。

思考

まず、修正操作なしで、その後、裸の点線のルール(ある点線のルールの研究ノート)。

操作、そこ変更分割統治の動的ポイント

基本的な考え方は、動的ポイント(個人要約)を分割することです:あなたが最初の重心を見つけることができるので、ツリーは、変更されません、およびビルドが通り木が点在(各層の重心を結ぶ木)、分割統治の後、メンテナンスポイントを時間再帰検索廃棄物に起因する重心を避け、データを知っておく必要があります。

基本的な考え方は単純で、データを要約することは困難であると彼らは維持するために知っておく必要があります。

(注:特に以下を指定しない場合、「息子」、「サブツリー」、「父」、「距離」および他の用語は、元のツリーを参照)

この質問は、私たちはパーティション・プロセスのポイントである、知っている各ポイントのニーズのためのデータは次のとおりです。

  1. それはここで、重心位置にあるときにノードの管轄内黒色のに最大値と最大値から第二の距離データ1と呼ばれます。

  2. それは重力の中心にある場合、それの管轄内にあるすべてのポイント層の重心(すなわち、それはツリー父親点を指す)の距離は、データ2と呼びます。

これら二つのデータ間の関係は以下のとおりです。

彼自身のポイント2件のデータが最大に貢献する点線の木の父点線の木の父の各息子に応じて最大の貢献は、彼自身を与えるために、最大値と二番目に大きい値データ1を

明らかに、最大値と第2の最大値を取得する過程で、私たちはデータ構造をサポートしているの並べ替えを必要とする、ここでは使用することを選択したヒープを

私たちは、今述べてきた点線の木を、より明白な性質があります:その木の高さがある\(nはログ\ \)レベル。

その後、我々は、その祖先のそれぞれのデータを維持するために、ノードを変更する、およびのみができる場合(O(\ Nログ)\ \) の時間複雑さを。

ヒープ自体が削除操作をサポートしていないながら、しかし、保守プロセスでは、我々は、削除操作を使用する必要があります。

私たちは、ちょっとしたトリックを使用することができます。ヒープを置く二つの部分に 1があり、ソート・ヒープ 1は、ヒープを削除します

我々は値を削除する必要がある場合、値がちょうど必要な削除ヒープに参加するために

ソート・ヒープとスタックが削除した場合、最大値は、ときにヒープ要素の同じトップを、それがこの要素が削除されたことを意味し、それらの両方ポップ。

したがって、我々は時間の複雑さを取得します\(O(N \ログ^ 2 n個)\) アルゴリズム、およびスタック(プライオリティキュー)の使用、定数は比較的大きくなります。

ロス・バレーのコードの作者がします(TLE \)を\を通じてbzoj上のポイントを。そして、コードが比較的醜いです、理解するためにコードを見に推奨されていません。本当に羅区のコードに最初の問題への解決策を見てみたい、あなたは見ることができます。

コード

#include<bits/stdc++.h>
using namespace std;
const int _=1e5+7;
const int __=2e5+7;
const int L=20;
const int inf=0x3f3f3f3f;
struct hep{
  priority_queue<int> A,B;
  void push(int x){ A.push(x); }
  void del(int x){ B.push(x); }
  int top(){
    while(!A.empty()&&!B.empty()&&A.top()==B.top()){ A.pop(); B.pop(); }
    return A.empty() ?-1 :A.top();
  }
  int sec(){
    int x=top();
    if(x==-1) return x;
    A.pop();
    int y=top();
    A.push(x);
    return y;
  }
}h1[_],h2[_],ans;
int n,m,dep[_],f[_][L+7],dis[_],sz[_],rt,minx=inf,ft[_],lt[_];
int lst[_],nxt[__],to[__],tot;
bool vis[_],sta[_];
int gi(){
  char c=getchar(); int x=0,f=1;
  while(c<'0'||c>'9'){ f=c=='-'?-1:1; c=getchar(); }
  while(c>='0'&&c<='9'){ x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
  return x*f;
}
void add(int x,int y){ nxt[++tot]=lst[x]; to[tot]=y; lst[x]=tot; }
int Lca(int x,int y){
  if(dep[x]<dep[y]) swap(x,y);
  for(int i=L;i>=0;i--)
    if(dep[f[x][i]]>=dep[y])
      x=f[x][i];
  if(x==y) return x;
  for(int i=L;i>=0;i--)
    if(f[x][i]!=f[y][i]){
      x=f[x][i];
      y=f[y][i];
    }
  return f[x][0];
}
int dist(int x,int y){ return dep[x]+dep[y]-2*dep[Lca(x,y)]; }
void idk(int u,int fa){
  dep[u]=dep[fa]+1;
  f[u][0]=fa;
  for(int i=1;i<=L;i++)
    f[u][i]=f[f[u][i-1]][i-1];
  for(int i=lst[u];i;i=nxt[i]){
    int v=to[i];
    if(v==fa) continue;
    idk(v,u);
  }
}
void pre(int u,int fa,bool id){
  if(id) h1[rt].push(dis[u]+1); 
  sz[u]=1; dis[u]=dis[fa]+1;
  for(int i=lst[u];i;i=nxt[i]){
    int v=to[i];
    if(v==fa||vis[v]) continue;
    pre(v,u,id);
    sz[u]+=sz[v];
  }
}
void g_rt(int u,int fa,int sum){
  int maxn=sum-sz[u];
  for(int i=lst[u];i;i=nxt[i]){
    int v=to[i];
    if(v==fa||vis[v]) continue;
    g_rt(v,u,sum);
    maxn=max(maxn,sz[v]);
  }
  if(maxn<minx){ minx=maxn; rt=u; }
}
void upd(int u,int id){
  int t1=h2[u].top(),t2=h2[u].sec();
  if(id){
    if(t1==-1);
    else if(t2==-1) ans.push(0);
    else ans.push(t1+t2);
  }
  else{
    if(t1==-1);
    else if(t2==-1) ans.del(0);
    else ans.del(t1+t2);
  }
}
void init(int u,int lrt){
  minx=inf;
  pre(u,0,0);
  g_rt(u,0,sz[u]);
  //printf("u: %d rt: %d dis[rt]: %d\n",u,rt,dis[rt]);
  dis[rt]= lrt ?dis[rt] :-1;
  ft[rt]=lrt;
  lt[rt]=dis[rt]+1;    // 因为此时的 dis 是到 lrt 的子节点的距离, 所以要加上 1
  pre(rt,0,1);
  h2[lrt].push(h1[rt].top());
  vis[rt]=1; u=rt;
  for(int i=lst[u];i;i=nxt[i]){
    int v=to[i];
    if(vis[v]) continue;
    init(v,u);
  }
  vis[u]=0;
  h2[u].push(0);
  upd(u,1);
}
void modify(int u){
  sta[u]^=1;
  int len=lt[u],fa=ft[u],t=u;
  upd(u,0);
  //printf("%d %d\n",h2[u].top(),h2[u].sec());
  if(sta[u]){ h2[u].del(0); }
  else h2[u].push(0);
  upd(u,1);
  while(fa){
    int top=h1[u].top(),sec=h2[fa].sec();
    bool f1= len>=top,f2= len>=sec;
    if(f1){
      if(f2) upd(fa,0);
      h2[fa].del(top);
      if(sta[t]){ h1[u].del(len); h2[fa].push(h1[u].top()); }
      else{ h1[u].push(len); h2[fa].push(len); }
      if(f2) upd(fa,1);
    }
    else{
      if(sta[t]) h1[u].del(len);
      else h1[u].push(len);
    }
    u=ft[u]; fa=ft[u];
    len=dist(t,fa);
  }
}
char ss[_];
void run(){
  m=gi(); char c; int x;
  for(int i=1;i<=m;i++){
    //gets(ss);
    c=getchar();
    //printf("%s %c\n",ss,c);
    if(c=='G') printf("%d\n",ans.top());
    else{
      x=gi();
      //printf("x: %d\n",x);
      modify(x);
      //puts("!!!");
    }
  }
}
int main(){
  //freopen("x.in","r",stdin);
  //freopen("x.out","w",stdout);
  n=gi(); int x,y;
  for(int i=1;i<n;i++){
    x=gi(); y=gi();
    //printf("%d %d\n",x,y);
    add(x,y);
    add(y,x);
  }
  dis[0]=-1;
  idk(1,0);
  init(1,0);
  run();
  return 0;
}

おすすめ

転載: www.cnblogs.com/brucew-07/p/12121940.html