[dfs序 主席树] HackerRank University CodeSprint 3. Simple Tree Counting

Hillan大佬神奇的idea

求出树的dfs序,只要能处理加边和删边操作就行了

令加入的边为 (x,y) ( x , y ) ,不妨设 x x y 的父亲,令 z z x 所在联通块的根,那么 x x z 路径上的点权值都加上了 y y <script type="math/tex" id="MathJax-Element-24">y</script> 所在的联通块大小

这可以用dfs序维护

删边就一样了

用线段树维护,只要就可以可持久化了…

调了一天发现边的颜色没有可持久化…

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <assert.h>
#include <cstdlib>

using namespace std;

typedef long long ll;

const int N=240010,L=1000000;

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(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

int n,q,lst,p[N],lg2[N];
int st[N][25];

inline void Pre(){
  for(int i=1;i<=lst;i++) lg2[i]=lg2[i-1]+((1<<lg2[i-1]+1)==i);
  int t=lg2[lst];
  for(int i=1;i<=lst;i++) st[i][0]=p[i];
  for(int k=1;k<=t;k++)
    for(int i=1;i+(1<<k)-1<=lst;i++)
      st[i][k]=min(st[i][k-1],st[i+(1<<k-1)][k-1]);
}

inline int Min(int l,int r){
  int t=lg2[r-l+1];
  return min(st[l][t],st[r-(1<<t)+1][t]);
}

namespace S{
  int cnt,ls[N*100],rs[N*100];
  int tot[N*100],mn[N*100];

  inline int Min(int x,int l,int r){
    if(!x) return ::Min(l,r)-p[l-1];
    return mn[x];
  }

  inline int Tot(int g,int l,int r){
    if(!g) return p[r]-p[l-1];
    return tot[g];
  }

  pair<int,int> find(int g,int l,int r,int L,int R,int x){
    if(L==R) return make_pair(x+Min(g,L,R)<=0?L:-1,x+Tot(g,L,R));
    if(l==L && r==R){
      int mid=L+R>>1;
      if(Min(g,L,R)>-x) return make_pair(-1,x+Tot(g,L,R));
      if(Min(ls[g],L,mid)<=-x) return find(ls[g],l,mid,L,mid,x);
      return find(rs[g],mid+1,r,mid+1,R,x+Tot(ls[g],L,mid));
    }
    int mid=L+R>>1;
    if(r<=mid) return find(ls[g],l,r,L,mid,x);
    else if(l>mid) return find(rs[g],l,r,mid+1,R,x);
    pair<int,int> A=find(ls[g],l,mid,L,mid,x);
    if(~A.first) return A;
    return find(rs[g],mid+1,r,mid+1,R,x+A.second);
  }

  int Query(int g,int l,int r,int L,int R){
    if(!g) return p[r]-p[l-1];
    if(l==L && r==R) return tot[g];
    int mid=L+R>>1;
    if(r<=mid) return Query(ls[g],l,r,L,mid);
    else if(l>mid) return Query(rs[g],l,r,mid+1,R);
    else return Query(ls[g],l,mid,L,mid)+Query(rs[g],mid+1,r,mid+1,R);
  }

  void Add(int &g,int x,int L,int R,int y){
    int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k];
    tot[g]=Tot(k,L,R)+y;
    if(L==R) return mn[g]=tot[g],void();
    int mid=L+R>>1;
    if(x<=mid) Add(ls[g],x,L,mid,y); else Add(rs[g],x,mid+1,R,y);
    mn[g]=min(Tot(ls[g],L,mid)+Min(rs[g],mid+1,R),Min(ls[g],L,mid));
  }
}

int R[N];
int u[N],v[N],c[N],dpt[N],bg[N],ed[N],bl[N];

namespace C{
  int cnt,ls[N*100],rs[N*100],root[N*100];
  ll sum[N*100];

  ll find(int g,int l,int r,int c,int x){
    if(l==r) return S::find(root[g],x,lst,1,lst,0).first;
    int mid=l+r>>1;
    if(c<=mid) return find(ls[g],l,mid,c,x);
    else return find(rs[g],mid+1,r,c,x);
  }

  int Query(int g,int l,int r,int L,int R,int c){
    if(L==R) return S::Query(root[g],l,r,1,lst);
    int mid=L+R>>1;
    if(c<=mid) return Query(ls[g],l,r,L,mid,c);
    else return Query(rs[g],l,r,mid+1,R,c);
  }

  void add(int &g,int x,int l,int r,ll y){
    int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k];
    sum[g]=sum[k]+y; root[g]=root[k];
    if(l==r) return ;
    int mid=l+r>>1;
    if(x<=mid) add(ls[g],x,l,mid,y); else add(rs[g],x,mid+1,r,y);
  }

  ll query(int g,int l,int r,int L,int R){
    if(l==L && r==R) return sum[g];
    int mid=L+R>>1;
    if(r<=mid) return query(ls[g],l,r,L,mid);
    else if(l>mid) return query(rs[g],l,r,mid+1,R);
    else return query(ls[g],l,mid,L,mid)+query(rs[g],mid+1,r,mid+1,R);
  }

  void Add(int &g,int c,int x,int L,int R,int y){
    int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k]; root[g]=root[k]; sum[g]=sum[k];
    if(L==R) return S::Add(root[g],x,1,lst,y);
    int mid=L+R>>1;
    if(c<=mid) Add(ls[g],c,x,L,mid,y);
    else Add(rs[g],c,x,mid+1,R,y);
  }
}

int G[N],cnt;

struct edge{
  int t,nx;
}E[N<<1];

inline void addedge(int x,int y){
  E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt;
}

void dfs(int x,int f){
  dpt[x]=dpt[f]+1; bg[x]=++lst; p[lst]++;
  for(int i=G[x];i;i=E[i].nx)
    if(E[i].t!=f) dfs(E[i].t,x);
  ed[x]=++lst; bl[lst]=x; p[lst]--;
}


ll calc(int x){ return 1LL*x*(x-1)/2; }

inline void addc(int &R,int x,int y,int c){
  int _x,_y,cur;
  if(dpt[x]>dpt[y]) swap(x,y);
  _x=bl[C::find(R,1,L,c,bg[x])];
  _y=y;
  int sx=C::Query(R,bg[_x],ed[_x]-1,1,L,c),sy=C::Query(R,bg[_y],ed[_y]-1,1,L,c);
  C::Add(R,c,ed[_y],1,L,sy); C::Add(R,c,ed[_x],1,L,-sy);
  C::add(R,c,1,L,calc(sx+sy)-calc(sx)-calc(sy));
}

inline void delc(int &R,int x,int y,int c){
  int _x,_y,cur;
  if(dpt[x]>dpt[y]) swap(x,y);
  _x=bl[C::find(R,1,L,c,bg[x])];
  _y=y;
  int sx=C::Query(R,bg[_x],ed[_x]-1,1,L,c),sy=C::Query(R,bg[_y],ed[_y]-1,1,L,c);
  C::Add(R,c,ed[_y],1,L,-sy); C::Add(R,c,ed[_x],1,L,sy);
  C::add(R,c,1,L,calc(sx-sy)+calc(sy)-calc(sx));
}

int rt[N];

namespace ED{
  int cnt,ls[N*30],rs[N*30],c[N*30];

  void cg(int &g,int x,int l,int r,int cc){
    int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k];
    if(l==r) return c[g]=cc,void("%%%vector");
    int mid=l+r>>1;
    if(x<=mid) cg(ls[g],x,l,mid,cc); else cg(rs[g],x,mid+1,r,cc);
  }

  int get(int g,int x,int l,int r){
    if(l==r) return c[g];
    int mid=l+r>>1;
    if(x<=mid) return get(ls[g],x,l,mid);
    else return get(rs[g],x,mid+1,r);
  }
}

int flg[N],ct;

int main(){
  read(n); 
  for(int i=1;i<n;i++){
    read(u[i]),read(v[i]),read(c[i]),addedge(u[i],v[i]);
    ED::cg(rt[0],i,1,n,c[i]);
  }
  dfs(1,0); //C::Build(); 
  for(int i=1;i<=lst;i++) p[i]+=p[i-1]; Pre();
  for(int i=1;i<n;i++) addc(R[0],u[i],v[i],c[i]);
  read(q);
  for(int k=1;k<=q;k++){
    R[k]=R[k-1]; rt[k]=rt[k-1];
    int opt; read(opt); 
    if(opt==1){
      flg[++ct]=k; 
      int i; read(i);
      c[i]=ED::get(rt[k],i,1,n);
      delc(R[k],u[i],v[i],c[i]);
      read(c[i]); ED::cg(rt[k],i,1,n,c[i]);
      addc(R[k],u[i],v[i],c[i]);
    }
    else if(opt==2){
      int l,r; read(l); read(r);
      printf("%lld\n",C::query(R[k],l,r,1,L));
    }
    else if(opt==3){
      int i; read(i); c[i]=ED::get(rt[k],i,1,n);
      int x=dpt[u[i]]<dpt[v[i]]?u[i]:v[i],_x;
      _x=bl[C::find(R[k],1,L,c[i],bg[x])];
      printf("%lld\n",calc(C::Query(R[k],bg[_x],ed[_x]-1,1,L,c[i])));
    }
    else{
      int i; read(i); R[k]=R[flg[i]-1]; rt[k]=rt[flg[i]-1];
    }
  }
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值