Colorful tree

cnbb 我被数组清零卡了一天..

子树改色询问子树颜色数..

先考虑颜色为x的节点对祖先答案的贡献,那么我们考虑把所有这些节点都搞出来,按dfs序排序,然后考虑每个节点a掌管的祖先是它和按dfs序的下一个同色节点b的LCA以下的节点,然后每个有颜色x儿子的树都被覆盖了,而且最多覆盖一次.

在删除节点的时候考虑将所有它的儿子删去变成一棵只有根节点的树.

统计答案的时候要考虑父亲的贡献..即若这个节点的颜色在它子树中出现了答案就不+1,否则答案+1.

cnbb的多组数据, fuck you.

数据复杂度(O((n+q)log{n}))

至于为什么是这样注意到加入节点的次数是(O(n+q))的,加入或删去一个节点的复杂度是(O(log{n}))的.

树上链加单点查询只需要考虑儿子对它所有祖先的贡献,然后改区间询问单点修改就可以了,BIT维护.

#include <set>
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
// Contants & usable functions
using namespace std;
const int N = 500010;
// Debug functions(mostly macros)
int out(int p){ return p; }
typedef int(*FII)(int);
#ifdef MacroDebug
#define debug(...) { fprintf(stderr, ##__VA_ARGS__); fflush(stdout); }
inline void printset(set<int> p, FII Fn=out){
	debug("Set :");
	for(set<int>::iterator k=p.begin();k!=p.end();++k) debug(" %d",Fn(*k));
	debug("
");
}
#else
#define debug(...)
inline void printset(set<int> p, FII Fn=out){}
#endif
// Tree(LCA, Left, Right, DfsSeq, Depth, Size)
struct ed{
	int t;
	ed*n;
}*h[N],Al[N<<1],*p=Al;
inline void ade(int f,int t){ *p=(ed){t,h[f]}; h[f]=p++; }
int DfsSeq[N<<1] , DfsMark ;
int Left  [N]    , Right[N];
int Father[N]    , Size [N];
int maxson[N]    , Depth[N];
int dfs(int t,int f=0){
	Father[t]=f, ++DfsMark, Size[t]=1, Depth[t]=Depth[f]+1;
	Left[DfsSeq[DfsMark]=t]=DfsMark;
	for(ed*i=h[t];i;i=i->n)if(i->t!=f){
		Size[t]+=dfs(i->t,t);
		if(Size[i->t]>Size[maxson[t]]) maxson[t]=i->t;
	} Right[t]=DfsMark;
	return Size[t];
}
inline void clearTree(){ for(int i=0;i<=DfsMark;++i) h[i]=NULL,Depth[i]=maxson[i]=Size[i]=0; p=Al; }

#ifdef MacroDebug
int OutUnSeq(int t){ return DfsSeq[t]; }
#else
const FII OutUnSeq=out;
#endif

int top[N];
int dfs2(int t,int Top){
	top[t]=Top;
	if(maxson[t]) dfs2(maxson[t],Top);
	for(ed*i=h[t];i;i=i->n)if(i->t!=Father[t]&&i->t!=maxson[t]) dfs2(i->t,i->t);
}
inline int LCA(int u,int v){
	int fu=top[u], fv=top[v];
	while(fu!=fv){
		if(Depth[fu]<Depth[fv]) swap(fu,fv),swap(u,v);
		u=Father[fu];
		fu=top[u];
	} return Depth[u]<Depth[v]?u:v;
}
// Path add, point query
#define lb(x) (x&-x)
template<int T=N<<1> struct BIT{
	int bitarr[T],siz;
	inline void clear(){ for(int i=0;i<=siz;++i) bitarr[i]=0; siz=0; }
	inline void init(int n){ clear(), siz=n; }
	inline void add(int t,int w){ for(;t<=siz;t+=lb(t)) bitarr[t]+=w; }
	inline int  sum(int t){ int ans=0; for(;t;t-=lb(t)) ans+=bitarr[t]; return ans; }
	inline int  sum(int l,int r){ return sum(r)-sum(l-1); }
};
BIT<> TPU;
inline void Add(int f,int t,int g=1){
	debug("1: %d %d %d
",f,t,g);
	TPU.add(Left[f],g);
	if(t) TPU.add(Left[t],-g);
}
inline int Qry(int f){ return TPU.sum(Left[f],Right[f]); }
// The colors on the tree
namespace colorSeg{
	int col[N<<2];
	void build(int i,int l,int r){
		col[i]=-1;
		if(l==r){
			col[i]=0;
			return;
		} int mid=(l+r)>>1;
		build(i<<1,l,mid), build(i<<1|1,mid+1,r);
	}
	inline void pd(int t){ if(~col[t]) col[t<<1]=col[t<<1|1]=col[t], col[t]=-1; }
	void upd(int i,int l,int r,int ql,int qr,int cl){
		if(ql<=l && r<=qr) col[i]=cl;
		else{ int mid=(l+r)>>1; pd(i);
			if(ql<=mid) upd(i<<1,l,mid,ql,qr,cl);
			if(qr> mid) upd(i<<1|1,mid+1,r,ql,qr,cl);
		}
	}
	int GetColor(int i,int l,int r,int t){ int mid=(l+r)>>1;
		if(l==r) return col[i];
		else return pd(i),(t<=mid)?GetColor(i<<1,l,mid,t):GetColor(i<<1|1,mid+1,r,t);
	}

	inline void set(int f,int val){ upd(1,1,DfsMark,Left[f],Right[f],val); }
	inline int  get(int f){ return GetColor(1,1,DfsMark,Left[f]); }
};
// Stores All Colors & Deletable Tree
typedef set<int> si;
typedef si::iterator sit;
si colors[N];
int Pcolor[N];
int PathUpto[N];
inline void Reinit(int nk){ for(int i=1;i<=nk;++i) colors[i].clear(), PathUpto[i]=-1; }
inline void ReColor(int q,int RecolorQ=-1){
	debug("Recolor %d -- %d
",q,RecolorQ);
	if(~PathUpto[q]){
		debug("FStart
");
		Add(q,PathUpto[q],-1), PathUpto[q]=-1;
		colors[Pcolor[q]].erase(Left[q]);
		debug("Color %d ",Pcolor[q]);
		printset(colors[Pcolor[q]],OutUnSeq);
		debug("FEnd
");
	} if(~RecolorQ) Pcolor[q]=RecolorQ;
	if(Pcolor[q]){
		int colorx=Pcolor[q];
		debug("Color %d ",colorx);
		printset(colors[colorx],OutUnSeq);
		sit v=colors[colorx].lower_bound(Left[q]);
		if(v!=colors[colorx].end()){
			int ar=DfsSeq[*v];
			PathUpto[q]=LCA(q,ar);
		}else PathUpto[q]=0;
		debug("Update PathUpto %d
",PathUpto[q]);
		Add(q,PathUpto[q]);
		colors[colorx].insert(Left[q]);
	}
}
inline void deletePoint(int t){
	if(int qc=Pcolor[t]){
		ReColor(t,0);
		sit k=colors[qc].lower_bound(Left[t]);
		if(k!=colors[qc].begin()) ReColor(DfsSeq[*(--k)]);
	}
}
inline void insertPoint(int t,int color){
	deletePoint(t);
	if(color){
		ReColor(t,color);
		debug("Color %d Find %d ",color,t);
		printset(colors[color],OutUnSeq);
		sit v=colors[color].find(Left[t]);
		if(v!=colors[color].begin()) ReColor(DfsSeq[*(--v)]);
	}
}
namespace treeSeg{
	int Has[N<<2];
	void build(int i,int l,int r){
		Has[i]=0; int mid=(l+r)>>1;
		if(l==r) return;
		build(i<<1,l,mid), build(i<<1|1,mid+1,r);
	}
	int sum(int i,int l,int r,int ql,int qr,int ans=0){ int mid=(l+r)>>1;
		if(ql<=l && r<=qr) return Has[i];
		else{
			if(ql<=mid) ans+=sum(i<<1,l,mid,ql,qr);
			else ans+=sum(i<<1|1,mid+1,r,ql,qr);
			return ans;
		}
	}
	int clr(int i,int l,int r,int ql,int qr){ int mid=(l+r)>>1;
		if(l==r) deletePoint(DfsSeq[l]),Has[i]=0;
		else{
			if(ql<=mid && Has[i<<1]) clr(i<<1,l,mid,ql,qr);
			if(qr> mid && Has[i<<1|1]) clr(i<<1|1,mid+1,r,ql,qr);
			Has[i]=Has[i<<1]+Has[i<<1|1];
		}
	}
	void set(int i,int l,int r,int t){
		if(l==r){
			Has[i]=1;
			return;
		}
		int mid=(l+r)>>1;
		if(t<=mid) set(i<<1,l,mid,t);
		else set(i<<1|1,mid+1,r,t);
		Has[i]=Has[i<<1]+Has[i<<1|1];
	}
	inline void Color(int f){ set(1,1,DfsMark,Left[f]); }
	inline void Delete(int f){ if(Left[f]==Right[f]) return; clr(1,1,DfsMark,Left[f]+1,Right[f]); }
};
inline void Color(int f,int val){
	insertPoint(f,val);
	treeSeg::Delete(f);
	treeSeg::Color (f);
	colorSeg::set(f,val);
}
inline int  Query(int f){
	int ccol=colorSeg::get(f);
	int target=0x7fffffff;
	sit v=colors[ccol].lower_bound(Left[f]);
	if(v!=colors[ccol].end()) target=*v;
	return (Qry(f)+1)-(target<=Right[f]?1:0);
}
inline void Work(int t){
	static int vc[N];
	printf("Case #%d:
",t);
	clearTree();
	int n; scanf("%d",&n);
	for(int i=1,a,b;i<n;++i){
		scanf("%d%d",&a,&b);
		ade(a,b); ade(b,a);
	}
	DfsMark=0;
	dfs(1), dfs2(1,1);
	TPU.init(DfsMark);
	colorSeg::build(1,1,DfsMark);
	treeSeg ::build(1,1,DfsMark);
	Reinit(n);
	for(int i=1;i<=n;++i)
		colors[i].clear();
	for(int i=1;i<=n;++i)
		scanf("%d",vc+i), Pcolor[i]=0;
	for(int i=1;i<=n;++i)
		Color(DfsSeq[i],vc[DfsSeq[i]]);
	int q; scanf("%d",&q);
	for(int i=1;i<=q;++i){
		int a,u,c;
		scanf("%d%d",&a,&u);
		if(a){
			int q=Query(u);
			printf("%d
",q);
			debug("%d
",q);
		}
		else scanf("%d",&c),Color(u,c);
	}
}
int main(){
	int t; scanf("%d",&t);
	for(int i=1;i<=t;++i) Work(i);
	return 0;
}
原文地址:https://www.cnblogs.com/tmzbot/p/5575226.html