[JLOI2014]松鼠的新家(线段树,树链剖分)
题目描述
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。
松鼠想邀请****前来参观,并且还指定一份参观指南,他希望**能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家。可是这样会导致**重复走很多房间,懒惰的**不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。
**是个馋家伙,立马就答应了。现在松鼠希望知道为了保证**有糖果吃,他需要在每一个房间各放至少多少个糖果。
因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当**在参观的最后到达餐厅时就不需要再拿糖果吃了。
输入输出格式
输入格式:
第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an
接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。
输出格式:
一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让**有糖果吃。
思路:
又是一道树剖板子题
对于**的访问,我们可以看成是从在a[i]~a[i+1]的路径上都增加了1
然后由于有重复,将每次将a[i+1]减1就好
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<bitset> #include<queue> #include<algorithm> //#define int long long #define rii register int i #define rij register int j using namespace std; int n; struct ljb{ int to,nxt; }x[900005]; struct node{ int val,lazy; }y[1200005]; int f[300005],sd[300005],head[300005],val[300005],size[300005]; int weison[300005],cnt,bnt,nid[300005],nval[300005],ntop[300005]; int sx[1000005]; int res; void add(int from,int to) { cnt++; x[cnt].to=to; x[cnt].nxt=head[from]; head[from]=cnt; } void dfs1(int wz,int fa,int s) { sd[wz]=s; f[wz]=fa; size[wz]=1; int maxn=0; for(rii=head[wz];i!=0;i=x[i].nxt) { int to=x[i].to; if(to==fa) { continue; } dfs1(to,wz,s+1); size[wz]+=size[to]; if(size[to]>maxn) { maxn=size[to]; weison[wz]=to; } } } void dfs2(int wz,int top) { bnt++; nid[wz]=bnt; nval[bnt]=val[wz]; ntop[wz]=top; if(weison[wz]==0) { return; } dfs2(weison[wz],top); for(rii=head[wz];i!=0;i=x[i].nxt) { int to=x[i].to; if(weison[wz]==to||f[wz]==to) { continue; } dfs2(to,to); } } void build(int bh,int l,int r) { if(l==r) { y[bh].val=nval[l]; return; } int mid=(l+r)/2; build(bh*2,l,mid); build(bh*2+1,mid+1,r); y[bh].val+=y[bh*2].val+y[bh*2+1].val; } void pushdown(int bh,int cd) { y[bh*2].lazy+=y[bh].lazy; y[bh*2+1].lazy+=y[bh].lazy; y[bh*2].val+=y[bh].lazy*(cd-(cd/2)); y[bh*2+1].val+=y[bh].lazy*(cd/2); y[bh].lazy=0; } void updata(int bh,int nl,int nr,int l,int r,int val) { int len=(nr-nl+1); if(l<=nl&&nr<=r) { y[bh].lazy+=val; y[bh].val+=val*len; return; } if(y[bh].lazy!=0) { pushdown(bh,len); } int mid=(nl+nr)/2; if(l<=mid) { updata(bh*2,nl,mid,l,r,val); } if(r>mid) { updata(bh*2+1,mid+1,nr,l,r,val); } y[bh].val=(y[bh*2].val+y[bh*2+1].val); } void query(int bh,int nl,int nr,int l,int r) { if(l<=nl&&r>=nr) { res+=y[bh].val; return; } int mid=(nl+nr)/2; if(y[bh].lazy!=0) { pushdown(bh,nr-nl+1); } if(l<=mid) { query(bh*2,nl,mid,l,r); } if(r>mid) { query(bh*2+1,mid+1,nr,l,r); } } int querylj(int from,int to) { int ans=0; while(ntop[from]!=ntop[to]) { if(sd[ntop[from]]<sd[ntop[to]]) { swap(from,to); } res=0; query(1,1,n,nid[ntop[from]],nid[from]); ans+=res; from=f[ntop[from]]; } if(sd[from]>sd[to]) { swap(from,to); } res=0; query(1,1,n,nid[from],nid[to]); ans+=res; return ans; } void addlj(int from,int to,int val) { while(ntop[from]!=ntop[to]) { if(sd[ntop[from]]<sd[ntop[to]]) { swap(from,to); } updata(1,1,n,nid[ntop[from]],nid[from],val); from=f[ntop[from]]; } if(sd[from]>sd[to]) { swap(from,to); } updata(1,1,n,nid[from],nid[to],val); } signed main() { scanf("%d",&n); for(rii=1;i<=n;i++) { scanf("%d",&sx[i]); } for(rii=1;i<n;i++) { int fe,to; scanf("%d%d",&fe,&to); add(fe,to); add(to,fe); } dfs1(1,0,2); dfs2(1,1); build(1,1,n); for(rii=1;i<n;i++) { addlj(sx[i],sx[i+1],1); addlj(sx[i+1],sx[i+1],-1); } for(rii=1;i<=n;i++) { printf("%d\n",querylj(i,i)); } }