[树链剖分 可持久化线段树 垃圾数据结构题] Codechef JUNE17 #OAK Persistent oak

垃圾数据结构题

大概就是维护树上的点离最大承重还差多少
然后断掉的就是到根路径上最早的小于0的地方
断掉后 到根路径还剩的承重都要加上掉下的重量
就是一颗线段树满足区间加 区间求min

鄙视CC强行可持久化 硬上主席树标记永久化
有个trick 就是一个子树抖落之后 那么这一整棵子树也就是一段区间还原成初始值 这个很难打标记 那么就把初始版本的主席树的相应节点接过来就好了

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;

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,next;
}G[N<<1];
int head[N],inum;
inline void add(int u,int v,int p){
  G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
#define V G[p].v
ll val[N];
int size[N],pre[N],clk;
int back[N];

int fat[N],top[N];

inline void dfs(int u){
  size[u]=1;
  for (int p=head[u];p;p=G[p].next)
    fat[V]=u,dfs(V),size[u]+=size[V];
}
inline void find(int u,int z){
  pre[u]=++clk; back[clk]=u; top[u]=z;
  int son=-1,maxv=0;
  for (int p=head[u];p;p=G[p].next)
    if (size[V]>maxv)
      maxv=size[son=V];
  if (son!=-1) find(son,z);
  for (int p=head[u];p;p=G[p].next)
    if (V!=son)
      find(V,V);
}

const int M=30000005;

int n,m;

namespace SEG1{
  int rt[N],ncnt;
  int ls[M],rs[M]; ll T[M],F[M];
  inline void Build(int &x,int l,int r){
    x=++ncnt;
    if (l==r){
      T[x]=val[back[l]]; return;
    }
    int mid=(l+r)>>1;
    Build(ls[x],l,mid); Build(rs[x],mid+1,r);
    T[x]=min(T[ls[x]],T[rs[x]])+F[x];
  }
  inline void Clear(int &x,int y,int z,ll tag,int l,int r,int ql,int qr){
    if (ql<=l && r<=qr){
      x=++ncnt; ls[x]=ls[z]; rs[x]=rs[z];
      F[x]=-tag; T[x]=T[z]-tag;
      return;
    }
    x=++ncnt; T[x]=T[y]; F[x]=F[y]; ls[x]=ls[y]; rs[x]=rs[y]; 
    int mid=(l+r)>>1;
    if (ql<=mid) Clear(ls[x],ls[y],ls[z],tag+F[x],l,mid,ql,qr);
    if (qr>mid) Clear(rs[x],rs[y],rs[z],tag+F[x],mid+1,r,ql,qr);
    T[x]=min(T[ls[x]],T[rs[x]])+F[x];
  }
  inline void Add(int &x,int y,int l,int r,int ql,int qr,int a){
    x=++ncnt; F[x]=F[y]; T[x]=T[y]; ls[x]=ls[y]; rs[x]=rs[y];
    if (ql<=l && r<=qr){
      F[x]+=a; T[x]+=a;
      return;
    }
    int mid=(l+r)>>1;
    if (ql<=mid) Add(ls[x],ls[y],l,mid,ql,qr,a);
    if (qr>mid) Add(rs[x],rs[y],mid+1,r,ql,qr,a);
    T[x]=min(T[ls[x]],T[rs[x]])+F[x];
  }
  ll Ret=0,W;
  inline void find(int x,int l,int r,ll tag){
    if (l==r){
      Ret=l; return;
    }
    int mid=(l+r)>>1;
    if (T[rs[x]]+F[x]+tag<W)
      find(rs[x],mid+1,r,tag+F[x]);
    else
      find(ls[x],l,mid,tag+F[x]);
  }
  inline void Query(int x,int l,int r,ll tag,int ql,int qr){
    if (ql<=l && r<=qr){
      if (!Ret && T[x]+tag<W)
    find(x,l,r,tag);
      return;
    }
    int mid=(l+r)>>1,ret=1<<30;
    if (qr>mid) Query(rs[x],mid+1,r,tag+F[x],ql,qr);
    if (ql<=mid) Query(ls[x],l,mid,tag+F[x],ql,qr);
  }
  inline int QQ(int x,int u,int w){
    W=w;
    while (u!=-1){
      Ret=0; Query(x,1,n+1,0,pre[top[u]],pre[u]);
      if (Ret) return back[Ret];
      u=fat[top[u]];
    }
    return 0;
  }
  inline void AA(int i,int s,int u,int W){
    rt[i]=rt[s];
    while (u!=-1){
      Add(rt[i],rt[i],1,n+1,pre[top[u]],pre[u],W);
      u=fat[top[u]];
    }
  }
}

namespace SEG2{
  int rt[N],ncnt;
  ll sum[M]; int ls[M],rs[M];
  inline void Build(int &x,int l,int r){
    x=++ncnt; sum[x]=0; ls[x]=rs[x]=0;
    if (l==r) return;
    int mid=(l+r)>>1;
    Build(ls[x],l,mid); Build(rs[x],mid+1,r);
  }
  inline void Add(int &x,int y,int l,int r,int t,int a){
    x=++ncnt; sum[x]=sum[y]+a; ls[x]=ls[y]; rs[x]=rs[y];
    if (l==r) return;
    int mid=(l+r)>>1;
    if (t<=mid)
      Add(ls[x],ls[y],l,mid,t,a);
    else
      Add(rs[x],rs[y],mid+1,r,t,a);
  }
  ll Ret=0;
  inline void Clear(int &x,int y,int z,int l,int r,int ql,int qr){
    if (ql<=l && r<=qr){
      Ret+=sum[y]; x=z; return;
    }
    x=++ncnt; ls[x]=ls[y]; rs[x]=rs[y]; 
    int mid=(l+r)>>1;
    if (ql<=mid) Clear(ls[x],ls[y],ls[z],l,mid,ql,qr);
    if (qr>mid) Clear(rs[x],rs[y],rs[z],mid+1,r,ql,qr);
    sum[x]=sum[ls[x]]+sum[rs[x]];
  }
}

int main(){
  int T,s,order,x,y;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(T);
  while (T--){
    read(n); read(m); val[0]=1LL<<60;
    for (int i=1;i<=n;i++)
      read(x),read(y),add(x,i,++inum),val[i]=y;
    fat[0]=-1; dfs(0); find(0,0);
    SEG1::Build(SEG1::rt[0],1,n+1);
    SEG2::Build(SEG2::rt[0],1,n+1);
    for (int i=1;i<=m;i++){
      read(s); read(order); read(x);
      if (order==1){
    read(y);
    int u=SEG1::QQ(SEG1::rt[s],x,y);
    printf("%d\n",u);
    if (u){
      x=u;
      SEG2::Ret=0;
      SEG2::Clear(SEG2::rt[i],SEG2::rt[s],SEG2::rt[0],1,n+1,pre[x],pre[x]+size[x]-1);
      ll sum=SEG2::Ret;
      SEG1::Clear(SEG1::rt[i],SEG1::rt[s],SEG1::rt[0],0,1,n+1,pre[x],pre[x]+size[x]-1);
      SEG1::AA(i,i,fat[x],sum);
    }else{
      SEG1::AA(i,s,x,-y);
      SEG2::Add(SEG2::rt[i],SEG2::rt[s],1,n+1,pre[x],y);
    }
      }else if (order==2){
    SEG2::Ret=0;
    SEG2::Clear(SEG2::rt[i],SEG2::rt[s],SEG2::rt[0],1,n+1,pre[x],pre[x]+size[x]-1);
    ll sum=SEG2::Ret;
    SEG1::Clear(SEG1::rt[i],SEG1::rt[s],SEG1::rt[0],0,1,n+1,pre[x],pre[x]+size[x]-1);
    SEG1::AA(i,i,fat[x],sum);
    printf("%d\n",sum);
      }
    }
    SEG1::ncnt=SEG2::ncnt=0;
    cl(SEG1::rt); cl(SEG2::rt);
    clk=0; cl(head); inum=0;
  }
  return 0;
}

一开始不会求min打加减标记 先写了个naive的

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

#define read(x) scanf("%d",&(x))

const int N=100005;
const int M=10000005;

int rt[N],ncnt;
int ls[M],rs[M],T[M],F[M];

inline void Add(int &x,int y,int l,int r,int ql,int qr,int a){
  x=++ncnt; F[x]=F[y]; T[x]=T[y]; ls[x]=ls[y]; rs[x]=rs[y];
  if (ql<=l && r<=qr){
    F[x]+=a; T[x]+=a;
    return;
  }
  int mid=(l+r)>>1;
  if (ql<=mid) Add(ls[x],ls[y],l,mid,ql,qr,a);
  if (qr>mid) Add(rs[x],rs[y],mid+1,r,ql,qr,a);
  T[x]=min(T[ls[x]],T[rs[x]])+F[x];
}
inline int Query(int x,int l,int r,int tag,int ql,int qr){
  if (ql<=l && r<=qr){
    return T[x]+tag;
  }
  int mid=(l+r)>>1,ret=1<<30;
  if (ql<=mid) ret=min(ret,Query(ls[x],l,mid,tag+F[x],ql,qr));
  if (qr>mid) ret=min(ret,Query(rs[x],mid+1,r,tag+F[x],ql,qr));
  return ret;
}

int n,m;


int main(){
  int order,l,r,x;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m);
  for (int i=1;i<=m;i++){
    read(order); read(l); read(r);
    if (order==1){
      read(x);
      Add(rt[i],rt[i-1],1,n,l,r,x);
    }else{
      rt[i]=rt[i-1];
      printf("%d\n",Query(rt[i],1,n,0,l,r));
    }
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值