BJOI2017 树的难题 点分治+线段树

原题:https://loj.ac/submission/420518

题解:要找到长度L-R的染色的最大权值。长度L-R肯定要用点分治,通过分析可以得出对于每一个子树,只要考虑当前分治中心到每颗子树的颜色是不是一样的就行了。即相同的要减去1个。我们考虑用两颗线段树维护。线段树的坐标表示长度。对于每一组询问,要从[max(0,L-num),y-num]中找到最大值。为了方便起见,把所有长度都+1。由于要在点分治加线段树,所以常数很大,能用的优化尽量用。。。代码量挺大的。在洛谷上过不去

#include
#pragma comment(linker, "/STACK:102400000,102400000")
#define inf 0x3f3f3f3f
#define reg register
using namespace std;

const int N=2e5+10;

struct E{int to,w,nxt;}data[N<<1];//w为颜色种类 

int n,m,L,R,len=1,rt,top,ans;
int clr[N],h[N],vis[N],f[N],sz[N];

inline int rd(){
	int x=0;int f=1;char s=getchar();
	while(!isdigit(s)) f=(s=='-'?-1:f),s=getchar();
	while(isdigit(s)) x=(x<<1)+(x<<3)+s-'0',s=getchar();
	return x*f;
}
inline void ins(int x,int y,int w){
	data[++len].to=y;data[len].w=w;data[len].nxt=h[x];h[x]=len;
	data[++len].to=x;data[len].w=w;data[len].nxt=h[y];h[y]=len;
} 

struct segmentTree{
	int tt[N<<2];bool tag[N<<2];
	#define ls now<<1
	#define rs now<<1|1
	#define mid (l+r)/2
	#define lson ls,l,mid
	#define rson rs,mid+1,r 
	inline void clear(){
		tag[1]=1;tt[1]=-inf;return ;
	}
	inline void pushdown(int now){
		if(tag[now]){
			tag[ls]=tag[rs]=1;tt[ls]=tt[rs]=-inf;tag[now]=0;
		} 
	}
	inline void upd(int now){
		tt[now]=max(tt[ls],tt[rs]);
	}
	inline void change(int now,int l,int r,int x,int c){
		if(l==x && r==x) {
			tt[now]=max(tt[now],c);return ;
		}
		tt[now]=max(tt[now],c);//常数优化 
		pushdown(now);
		if(x<=mid) change(lson,x,c);
		if(midy||y<0) return -inf;
		return query(1,1,R+1,max(1,x+1),y+1);
	}
	#undef ls
	#undef rs
	#undef lson
	#undef rson
	#undef mid 
}A,B;//A表示不同颜色的,B相同颜色来自不同的 
struct node{
	int dis,num,from,c;//从哪来的边 
}a[N];
bool cmp(node x,node y){//按颜色为第一关键字,来的边为第二关键字 
	return x.c==y.c?x.fromf[x]) rt=x;
}
// dis距离 num长度 fclr 上一个的颜色 
void dfs(int x,int fa,int dis,int num,int fclr,int from,int c){
	if(num>R) return ;
	a[++top]=(node){dis,num,from,c};
	for(reg int i=h[x];i;i=data[i].nxt){
		int y=data[i].to;if(vis[y] || y==fa) continue;
		int w=data[i].w;
		if(fclr != w) dfs(y,x,dis+clr[w],num+1,w,from,c);
		else  dfs(y,x,dis,num+1,w,from,c);
	} 
}

void work(int x){
	a[top=1]=(node){0,0,0,0};
	for(int i=h[x];i;i=data[i].nxt){
		int y=data[i].to;if(vis[y]) continue;
		int w=data[i].w;
		dfs(y,x,clr[w],1,w,i,w);
	}
	sort(a+1,a+top+1,cmp);
	A.clear();B.clear();
	for(reg int l=1,r;l<=top;l=r+1){
		for(r=l;r

 

你可能感兴趣的:(点分治,线段树)