[NOIP2016] 사랑의 문제 해결은 매일 보고서를 실행

문제의 의미

A는 \ (N- \) 트리의 노드, 관찰자의 트리의 각 노드, 각 관측 시간에 대한 관찰자 \ (time_i \) ,

\ (m \) 플레이어, 각 플레이어 \ (0 \) 시작 지점에서 시간 때 \ (S_I는 \) 노드를 통해 매번 실행을 시작, 가장 짧은 경로를 따라 끝 지점 \ (t_i \) 달렸다.

각 관찰자가 관찰 할 수에 대한 선수의 번호가 필요.

사고

폭력 열거 경로 각각의 플레이어가 있어야합니다 \ (O (N ^ 2) \) , 그리고 가능하지,
다음 고려 열거 모든 관찰자 관찰 할 수있는 방법을 많은 선수 부탁드립니다.

관찰자 경우 \ (X는 \) 위치 \ (S_I \)(lca_i \) \ 경로 다음 \ (X \) 관찰 \ (I \) 조건
\ [time_x dep_ = {s_i} - dep_x \]
전환은 약해진다
\ [time_x dep_x + = S_I dep_ {} \]

만약 \ (X \) 위치 \ (t_i \)(lca_i \) \ 경로 다음 \ (X \) 관찰 \ (I \) 조건
\ [time_x dis_ = {s_i \ 에 t_i} - (dep_t - dep_x) \]
변환
\ [time_x - dep_x = DIS - dep_t dep_s = - 2 * dep_ lca_i {} \]

나무 차이처럼 보인다는 각 지점에 대한 열거 하위 트리 오픈 배럴 잘을 기록합니다.

그러나 버킷 지점으로 현재의 열거에 영향을 미칠 것입니다 전에,하는 문제가있다.

내 방식 바보 비교, 대량 주문에 작은 차이의 가치, 그 다음 모든 펜윅 트리 쿼리.

사실, 우리는 현재의 지점이 두 라인에 자신의 값의 값 이상, 전체 배럴이 필요하지 않습니다에 대해 생각합니다.

우리는 그 가치에 대해 처음 두 기록을 한 다음 하위 트리를 열거 한 다음 두 개의 값을 확인 후, 라인에 차이를 발견 할 때 각 지점을 열거 할 필요가 그래서.

코드

\ (O는 (n \) N 기록 \)

#include<bits/stdc++.h>
#define pb push_back
#define sz size
using namespace std;
const int N=299998+7;
const int L=20;
int n,m,dep[N],dfn[N],en[N],cnt,tme[N],f[N][L+7],ans[N],s[N],t[N],lca[N],qes[N],poi[N];
int t1[N],t2[N],c[N];
int lst[N],nxt[2*N],to[2*N],tot;
vector<int> p[N];
void add(int x,int y){ nxt[++tot]=lst[x]; to[tot]=y; lst[x]=tot; }
void pre(int u,int fa){
  dep[u]=dep[fa]+1;
  dfn[u]=++cnt;
  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;
    pre(v,u);
  }
  en[u]=cnt;
}
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];
}
bool rulea(int a,int b){ return tme[a]+dep[a]<tme[b]+dep[b]; }
bool ruleb(int a,int b){ return tme[a]-dep[a]<tme[b]-dep[b]; }
bool rule1(int a,int b){ return t1[a]<t1[b]; }
bool rule2(int a,int b){ return t2[a]<t2[b]; }
void modify(int x,int w){
  if(!x) return;
  for(int i=x;i<=n;i+=i&-i){
    c[i]+=w;
  }}
int sum(int x){
  if(!x) return 0;
  int res=0;
  for(int i=x;i;i-=i&-i)
    res+=c[i];
  return res;
}
int query(int l,int r){
  return sum(r)-sum(l-1);
}
int main(){
  //freopen("run1.in","r",stdin);
  //freopen("run.out","w",stdout);
  cin>>n>>m;
  int x,y;
  for(int i=1;i<n;i++){
    scanf("%d%d",&x,&y);
    add(x,y); add(y,x);
  }
  pre(1,0);
  for(int i=1;i<=n;i++){ qes[i]=i; scanf("%d",&tme[i]); }
  for(int i=1;i<=m;i++){
    scanf("%d%d",&s[i],&t[i]);
    lca[i]=Lca(s[i],t[i]);
    poi[i]=i;
    t1[i]=dep[s[i]];
    t2[i]=dep[s[i]]-2*dep[lca[i]];
  }
  sort(qes+1,qes+1+n,rulea);
  sort(poi+1,poi+1+m,rule1);
  int now=1;
  for(int i=1;i<=n;i++){
    int tmp=tme[qes[i]]+dep[qes[i]];
    while(now<=m&&t1[poi[now]]<tmp) now++;
    int lt=now;
    for(;now<=m&&t1[poi[now]]==tmp;now++){
      modify(dfn[s[poi[now]]],1);
      modify(dfn[f[lca[poi[now]]][0]],-1);
    }
    while(i<=n&&tme[qes[i]]+dep[qes[i]]==tmp){ ans[qes[i]]+=query(dfn[qes[i]],en[qes[i]]); i++; }
    i--;
    for(;lt<now;lt++){
      modify(dfn[s[poi[lt]]],-1);
      modify(dfn[f[lca[poi[lt]]][0]],1);
    }
  }
  sort(qes+1,qes+1+n,ruleb);
  sort(poi+1,poi+1+n,rule2);
  now=1;
  for(int i=1;i<=n;i++){
    int tmp=tme[qes[i]]-dep[qes[i]];
    while(now<=m&&t2[poi[now]]<tmp) now++;
    int lt=now;
    for(;now<=m&&t2[poi[now]]==tmp;now++){
      modify(dfn[t[poi[now]]],1);
      modify(dfn[lca[poi[now]]],-1);
    }
    while(i<=n&&tme[qes[i]]-dep[qes[i]]==tmp){ ans[qes[i]]+=query(dfn[qes[i]],en[qes[i]]); i++; }
    i--;
    for(;lt<now;lt++){
      modify(dfn[t[poi[lt]]],-1);
      modify(dfn[lca[poi[lt]]],1);
    }
  }
  for(int i=1;i<=n;i++) printf("%d ",ans[i]); putchar('\n');
  return 0;
}

\ (O (n) \)

우리는 그것을 해결하기 위해 시간을 가지고있다.

추천

출처www.cnblogs.com/brucew-07/p/11908901.html