BZOJ 3631 [JLOI2014]松鼠的新家==樹剖

題目傳送門:23333


十分考驗樹剖的本事

在網上看到幾個大神寫樹剖T掉了233333

主要是樹剖,剖完後把一條路上的點不停地打永久標記,不用向下推,查詢時直接把flag加起來就好了。

另外除了第一個點外其餘點都要減一,中間的點進入會拿一顆糖,出時也會計算一個,所以要減去。

最後一個房間的糖題目說了不用,所以也要減。

(雖說被這個坑了好久QAQ)



#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#define rep(j,k,l) for (int j=k;j<=l;j++)
#define N 300005

using namespace std;
struct _233{
	
	int l,r,flag;
	
} tr[N*4];
int n,cnt,a[N],ne[N*2],to[N*2],st[N];
int as[N],size[N],son[N],deep[N],fa[N],top[N],dfn[N],id[N];

void add(int k,int l,int p){
	
	to[p]=l;
	ne[p]=st[k];
	st[k]=p;
	
}

void dfs1(int rt,int dad){
	
	size[rt]=1;
	fa[rt]=dad;
	deep[rt]=deep[dad]+1;
	son[rt]=0;int _=0;
	for (int i=st[rt];i!=0;i=ne[i])
		if (to[i]!=dad){
			
			dfs1(to[i],rt);
			size[rt]+=size[to[i]];
			if (size[to[i]]>_){
				
				_=size[to[i]];
				son[rt]=to[i];
				
			}
			
		}
	
}

void dfs2(int rt,bool qaz){
	
	if (qaz) top[rt]=top[fa[rt]];
	else top[rt]=rt;
	dfn[++cnt]=rt;
	id[rt]=cnt;
	if (son[rt]!=0) dfs2(son[rt],1);
	for (int i=st[rt];i!=0;i=ne[i])
		if (to[i]!=fa[rt]&&to[i]!=son[rt])
			dfs2(to[i],0);
	
}

void stree(int k,int l,int r){
	
	if (l==r) return;
	tr[k].l=++cnt;
	tr[k].r=++cnt;
	stree(tr[k].l,l,(l+r)/2);
	stree(tr[k].r,(l+r)/2+1,r);
	
}

void change(int k,int l,int r,int o,int p){
	
	if (o>r||p<l) return;
	if (o<=l&&r<=p){
		
		tr[k].flag+=1;
		return;
		
	}
	change(tr[k].l,l,(l+r)/2,o,p);
	change(tr[k].r,(l+r)/2+1,r,o,p);
	return;
	
}

void work(int x,int y){
	
	for (;top[x]!=top[y];x=fa[top[x]]){
		
		if (deep[top[x]]<deep[top[y]]) swap(x,y);
		change(1,1,n,id[top[x]],id[x]);
		//printf("%d %d\n",top[x],x);
		
	}
	change(1,1,n,min(id[x],id[y]),max(id[x],id[y]));
	//printf("%d %d\n",min(id[x],id[y]),max(id[x],id[y]));
	//printf("\n");
	
}

void print(int k,int l,int r,int f){
	
	if (l==r){
		
		if (dfn[l]==a[1]) f++;
		as[dfn[l]]=f+tr[k].flag;
		return;
		
	}
	print(tr[k].l,l,(l+r)/2,f+tr[k].flag);
	print(tr[k].r,(l+r)/2+1,r,f+tr[k].flag);
	
}

void tiaoshi(int k,int l,int r){
	
	printf("%d %d %d\n",l,r,tr[k].flag);
	if (l==r) return;
	tiaoshi(tr[k].l,l,(l+r)/2);
	tiaoshi(tr[k].r,(l+r)/2+1,r);
	
}

int main(){
	
	scanf("%d",&n);
	rep(i,1,n) scanf("%d",&a[i]);
	rep(i,1,n-1){
		
		int k,l;
		scanf("%d%d",&k,&l);
		add(k,l,2*i-1);
		add(l,k,2*i);
		
	}
	dfs1(1,0);
	dfs2(1,0);
	cnt=1;
	stree(1,1,n);
	//for(int i=1;i<=5;i++) printf("%d\n",top[i]);
	rep(i,2,n) work(a[i],a[i-1]);//tiaoshi(1,1,n),printf("\n");
	print(1,1,n,0);
	rep(i,1,n) printf("%d\n",as[i]-1);
	system("pause");
	
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章