Description
给你一棵包含N个节点的树,设每条边一开始的边权为0,现在有两种操作:
1)给出参数U,V,C,表示把U与V之间的路径上的边权变成C(保证C≥0)
2)给出参数U,V,C,表示把U与V之间的路径上的边权加上C。但是如果U至V之间路径某条边的边权加上C小于0,那么C=这条边的边权的相反数。
你需要统计出每次一操作过后树中边权为0的边有多少条。
Input
第一行两个整数N,M,分别表示表示节点个数与操作数。
接下来N-1行每行两个整数X,Y表示X,Y之间有一条边。
接下来M行每行4个整数P,U,V,C,P表示操作类型,U,V,C的意义见题目描述。
Output
输出文件包括M行,每行一个整数,表示边权为0的边的个数。
树链剖分+线段树维护一下区间最小值和个数、覆盖标记、加法标记
#include<cstdio> #include<algorithm> typedef long long i64; const int N=100007; const i64 fil_0=1ll<<60; char buf[6000007],*ptr=buf-1; int _(){ int x=0,c=*++ptr,f=1; while(c<48)c=='-'&&(f=-1),c=*++ptr; while(c>47)x=x*10+c-48,c=*++ptr; return x*f; } int n,m,es[N*2],enx[N*2],e0[N],ep=2,ans=0; int fa[N],sz[N],dep[N],top[N],son[N],id[N],idp=0; int _l,_r; i64 _a; struct node{ node*lc,*rc; i64 mn,fil,a; int L,R,mc; int c0(){ return mn?0:mc; } void _fil(i64 x){ mn=fil=x; mc=R-L+1; a=0; } void _add(i64 x){ if(fil!=fil_0)fil+=x; mn+=x;a+=x; } void fils(){ if(_l<=L&&R<=_r){ _fil(_a); return; } dn(); int M=L+R>>1; if(_l<=M)lc->fils(); if(_r>M)rc->fils(); up(); } void mns(){ if(mn>=_a)return; if(_l<=L&&R<=_r){ _a=mn; return; } dn(); int M=L+R>>1; if(_l<=M)lc->mns(); if(_r>M)rc->mns(); } void adds(){ if(_l<=L&&R<=_r){ _add(_a); return; } dn(); int M=L+R>>1; if(_l<=M)lc->adds(); if(_r>M)rc->adds(); up(); } void dn(){ if(a){ lc->_add(a); rc->_add(a); a=0; } if(fil!=fil_0){ lc->_fil(fil); rc->_fil(fil); fil=fil_0; } } void up(){ mn=lc->mn<rc->mn?lc->mn:rc->mn; mc=0; if(mn==lc->mn)mc+=lc->mc; if(mn==rc->mn)mc+=rc->mc; } }ns[N*2],*np=ns,*rt[N]; node*build(int L,int R){ node*w=np++; w->L=L;w->R=R; if(L!=R){ int M=L+R>>1; w->lc=build(L,M); w->rc=build(M+1,R); w->up(); }else{ w->mn=0;w->mc=1; w->fil=fil_0; } return w; } #define F(a,b) ans-=a->c0(),a->b(),ans+=a->c0() void fils(int x,int y,i64 c){ int a=top[x],b=top[y]; _a=c; while(a!=b){ if(dep[a]<dep[b])std::swap(a,b),std::swap(x,y); _l=id[a],_r=id[x]; F(rt[a],fils); x=fa[a];a=top[x]; } if(dep[x]>dep[y])std::swap(x,y); _l=id[x]+1,_r=id[y]; if(_l<=_r)F(rt[top[x]],fils); } void mns(int x,int y,i64 c){ int a=top[x],b=top[y]; _a=c; while(a!=b){ if(dep[a]<dep[b])std::swap(a,b),std::swap(x,y); _l=id[a],_r=id[x]; rt[a]->mns(); x=fa[a];a=top[x]; } if(dep[x]>dep[y])std::swap(x,y); _l=id[x]+1,_r=id[y]; if(_l<=_r)rt[top[x]]->mns(); } void adds(int x,int y,i64 c){ mns(x,y,-c); _a*=-1; int a=top[x],b=top[y]; while(a!=b){ if(dep[a]<dep[b])std::swap(a,b),std::swap(x,y); _l=id[a],_r=id[x]; F(rt[a],adds); x=fa[a];a=top[x]; } if(dep[x]>dep[y])std::swap(x,y); _l=id[x]+1,_r=id[y]; if(_l<=_r)F(rt[top[x]],adds); } void f1(int w,int pa){ dep[w]=dep[fa[w]=pa]+1; sz[w]=1; for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u!=pa){ f1(u,w); sz[w]+=sz[u]; if(sz[u]>sz[son[w]])son[w]=u; } } } void f2(int w,int tp){ top[w]=tp; id[w]=++idp; if(son[w])f2(son[w],tp); else rt[tp]=build(id[tp],id[w]); for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u!=fa[w]&&u!=son[w])f2(u,u); } } int main(){ buf[fread(buf,1,sizeof(buf),stdin)]=0; n=_();m=_(); for(int i=1,a,b;i<n;++i){ a=_();b=_(); es[ep]=b;enx[ep]=e0[a];e0[a]=ep++; es[ep]=a;enx[ep]=e0[b];e0[b]=ep++; } f1(1,0);f2(1,1); ans=n-1; for(int i=0,o,u,v,c;i<m;++i){ o=_();u=_();v=_();c=_(); if(o==1)fils(u,v,c); else adds(u,v,c); printf("%d\n",ans); } return 0; }