[杂题] AtCoder Grand Contest 007 E Shik and Travel

二分答案
然后每个子树维护二元组 (a,b) 表示存在一个进入该子树后,第一天花费为 a ,最后一天花费为 b ,中间天都满足相邻叶子距离小于等于 Mid
直接转移状态数太多,我们发现对于一个 a 只需要最小的 b ,一个 b 只需要最小的 a ,可以two-pointers合并
那么新的状态数 |S|2×min(|S1|,|S2|)
这样状态总数是 O(nlogn)
复杂度就是 O(nlognlogAns)
偷懒懒得归并排序,多一个log

#pragma GCC optimize(2)
#include
#include
#include
#include
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair abcd;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=100005;

struct edge{
  int u,v,w,next;
}G[N<<1];
int head[N],inum;
inline void add(int u,int v,int w,int p){
  G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}
#define V G[p].v

vector f[N];

inline bool cmp(abcd x,abcd y){
  return x.secondint n;
ll MID,minv[N];
int fat[N];

inline void Solve(vector &ab,vector &cd,vector &f){
  if (ab.size()>cd.size()) swap(ab,cd);
  sort(ab.begin(),ab.end(),cmp);
  sort(cd.begin(),cd.end());
  int n1=ab.size(),n2=cd.size(),pnt;
  minv[0]=cd[0].second;
  for (int i=1;i1],cd[i].second);
  pnt=n2-1;
  for (int i=0;iwhile (pnt>=0 && ab[i].second+cd[pnt].first>MID) pnt--;
    if (pnt>=0)
      f.pb(abcd(ab[i].first,minv[pnt]));
  }

  for (abcd &x:ab) swap(x.first,x.second);
  for (abcd &x:cd) swap(x.first,x.second);

  sort(ab.begin(),ab.end(),cmp);
  sort(cd.begin(),cd.end());
  minv[0]=cd[0].second;
  for (int i=1;i1],cd[i].second);
  pnt=n2-1;
  for (int i=0;iwhile (pnt>=0 && ab[i].second+cd[pnt].first>MID) pnt--;
    if (pnt>=0)
      f.pb(abcd(minv[pnt],ab[i].first));
  }
}
inline void dfs(int u){
  if (!head[u]) {
    f[u].pb(abcd(0,0));
    return;
  }
  int ls=0,rs=0,t1=0,t2=0;
  for (int p=head[u];p;p=G[p].next){
    dfs(V);
    if (!ls) ls=V,t1=G[p].w; else if (!rs) rs=V,t2=G[p].w;
  }
  vector &ab=f[ls],&cd=f[rs];
  for (abcd &x:ab) x.first+=t1,x.second+=t1;
  for (abcd &x:cd) x.first+=t2,x.second+=t2;
  Solve(ab,cd,f[u]);
}

int main(){
  int x,y;
  freopen("travel.in","r",stdin);
  freopen("travel.out","w",stdout);
  read(n);
  for (int i=2;i<=n;i++)
    read(fat[i]),read(y),add(fat[i],i,y,++inum);
  ll L=-1,R=1e10; 
  while (L+1if (L<1e6 && R>1e6) MID=1e6;
    else MID=(L+R)>>1;
    for (int i=1;i<=n;i++) f[i].clear();
    dfs(1);
    //printf("%d\n",f[1].size());
    if (!f[1].empty())
      R=MID;
    else
      L=MID;
  }
  printf("%lld\n",R);
  return 0;
}

你可能感兴趣的:(杂题)