[ZJOI2007] 숨기고 문제 해결보고 (동적 점 분할과 정복) 시크

[ZJOI2007] 숨바꼭질

최근 코드의 가장 큰 금액에 제목을 수행 (물론, 내가 못생긴 쓰기 ....)

문제의 의미

\ (N- \) 트리 노드 ( \ (N- \ 르. 5 ^ 10 \) ) 각 노드는 검은 색 또는 흰색입니다.

거기 \ (m \) 동작 ( \ (m \ 르. 5 \ 10 ^ 5 번 \) ), 두 개의 동작이 있으며,

  1. \ (X \) 색상 반전.
  2. 오른쪽 멀리 나무 검은 점 사이의 거리를 쿼리합니다.

사고

첫째, 수정 작업없이, 다음, 베어 점선 규칙입니다 ( 점선 규칙 연구 노트 ).

작동, 다음이 수정 분할과 정복의 동적 점을 .

나무가 먼저 무게 중심을 찾을 수 있도록, 변경, 빌드하지 않으므로 : 기본적인 아이디어는 동적 포인트 (개인 요약)를 분할하는 것입니다 점선 트리 (각 층의 무게 중심을 연결하는 나무), 분할 및 정복의 다음 유지 보수 지점을 필요가 시간 재귀 발견을 폐기물로 인한 무게 중심을 피하고, 데이터를 알고 있습니다.

기본적인 아이디어는 간단하다, 데이터를 요약하기 어려운 그들은 유지하기 위해 알 필요가있다.

(참고 : 아래에 달리 지정되지 않을 경우, "아들", "하위 트리", "아버지", "거리"등의 용어는 원래 나무 참조)

이 질문에, 우리는 파티션 프로세스의 지점에있다, 알고 각 지점의 요구에 대한 데이터는 다음과 같습니다

  1. 그것은하는 중력의 중심에있을 때 , 노드 관할 블랙 그 행 의 최대 값으로부터의 거리와 두 번째로 큰 값은 , 데이터 1이라고.

  2. 그 중심에있을 때, 그것을 관할하는 모든 점 층의 중심 (즉,이 트리 아버지 포인트 포인트 ) 데이터 (2)로 지칭 거리.

이들 두 데이터 사이의 관계가있다 :

자신의 지점 이 데이터를 최대 에 기여하는 점 나무 아버지 , 점선 나무 아버지의 각 아들에 따라 최대 기여는 자신에게주는 최대 값과 두 번째로 큰 값 데이터 1 .

분명히, 최대 값과 두 번째로 큰 값을 얻을 수있는 과정에서, 우리는 데이터 구조를 지원하는 일종의 필요, 여기에 우리가 사용하도록 선택할 .

우리는 방금 언급 한 점으로 나무를 좀 더 분명 성격이 : 그 나무의 높이 입니다 \ (N 로그 \ \) 수준.

다음 우리는 조상 각각의 데이터만을 유지하기 위해, 노드 수정 때 () O (\ 로그 n \를 \) 시간 복잡도.

힙 자체가 삭제 작업을 지원하지 않는 동안 그러나, 유지 보수 과정에서, 우리는 삭제 작업을 사용해야합니다.

우리는 약간의 트릭을 사용할 수 있습니다 : 힙을 넣어 두 부분으로 , 하나는 인 정렬 힙 , 하나는 힙을 삭제합니다 .

우리가 값을 삭제해야하는 경우, 값이 단지 필요가 삭제 힙에 가입 ,

정렬 힙 및 스택 삭제하면 최대 값이 때 힙 요소의 동일한 상단을 ,이 요소는, 그들은 둘 다 팝업 제거 된 것을 의미한다.

따라서, 우리는 시간 복잡도를 얻을 \ (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