垃圾数据结构题
大概就是维护树上的点离最大承重还差多少
然后断掉的就是到根路径上最早的小于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;
}