bzoj4353: Play with tree
2017-02-19 23:14
260 查看
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 ,ep=2,ans=0; int fa ,sz ,dep ,top ,son ,id ,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 ; 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; }
相关文章推荐
- bzoj 4353: Play with tree (树链剖分)
- 【Bzoj4353】play with tree
- 【BZOJ4353】Play with tree,树链剖分线段树
- [BZOJ4353]Play with tree(树链剖分+线段树)
- hdu 3487 Play with Chain splay tree
- hdu 3487 Play with Chain splay tree
- bzoj 4355: Play with sequence (线段树)
- 【BZOJ4355】Play with Sequence
- 【BZOJ】4355: Play with sequence
- hdu 3487 Play with Chain (Splay Tree easy)
- 【BZOJ4355】Play with sequence 线段树
- 【 bzoj 4355 】 Play with sequence - 线段树乱搞
- UVa 10673 Play with Floor and Ceil (数论)
- 【bzoj2588】Count on a tree 主席树
- Play 迷宫 with python and pygame
- [bzoj2654]tree(最小生成树+二分)
- [bzoj 2588] Spoj 10628. Count on a tree:函数式线段树
- BZOJ1977 [BeiJing2010组队]次小生成树 Tree
- [BZOJ2654]tree 最小生成树+贪心
- The import java.util.TreeSet conflicts with a type defined in the same file