[NOI2021] 轻重边

link

去年NOI的D1T1。其实感觉也没有那么难。

主要是如何快速修改路径上点的非路径连边。一个一个修改是不可能的,只能把边的修改转化成点的修改。于是想到每次修改都给路径上的点赋一个从未出现的颜色值,这样一来路径边和其它边就区分出来了:路径边的两端颜色相同,而其它边则两端颜色不同(这就体现出找从未出现过的颜色的重要性啦)。一开始由于默认的都是轻边,给每个点赋值不一样的颜色即可,到时候选颜色从 \(m+1\) 开始。

于是考虑线段树维护区间相同且相邻的元素对的个数,顺便记录区间的左右元素的颜色,合并的时候特判变化量即可。既然放在树上就要另外注意一些问题,比如两个点要分别维护ans,因为一个ans只能代表一条链(是指从lca到自身的这条链),然后在swap两个节点时两个ans也需要交换。最后两个点在一条重链上时要判断的是两个答案的左颜色是否相同。

许久未写树剖了,手生了,许多东西都淡忘了。好悲惨。记住while里判断的是两个点top的深度关系,记住线段树要开4倍。虽然这很简单,但我确实忘了。

除去这些应该还是比较好写的。

code

#include<bits/stdc++.h>
//#define zczc
const int N=100010;
using namespace std;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}
inline void swap(int &s1,int &s2){
	int s3=s1;s1=s2;s2=s3;return;
}

struct aa{
	int data,lc,rc;
}newone_aa,ss;
inline void swap_aa(aa &s1,aa &s2){
	aa s3=s1;s1=s2;s2=s3;return;
}
inline aa operator +(aa s1,aa s2){
	aa an;an.lc=s1.lc,an.rc=s2.rc;
	an.data=s1.data+s2.data+(s1.rc==s2.lc&&s1.rc!=0);
	return an;
}
inline void print(aa wh){
	printf("%d %d %d\n",wh.data,wh.lc,wh.rc);
}

#define lc (wh<<1)
#define rc (wh<<1|1)
#define mid (t[wh].l+t[wh].r>>1)
struct node{
	int l,r;
	bool lazy;int ly;
	aa data;
}t[N<<2],newone;
inline void pushup(int wh){
	t[wh].data=t[lc].data+t[rc].data;
}
inline void pushnow(int wh,int val){
	t[wh].lazy=true;t[wh].ly=val;
	t[wh].data=(aa){t[wh].r-t[wh].l,val,val};
}
inline void pushdown(int wh){
	if(t[wh].lazy){
		pushnow(lc,t[wh].ly);
		pushnow(rc,t[wh].ly);
		t[wh].lazy=false;
	}
}
inline void build(int wh,int l,int r){
	t[wh].data=(aa){0,l,r};
	t[wh].l=l,t[wh].r=r;
	t[wh].lazy=false;
	if(l==r)return;
	build(lc,l,mid);
	build(rc,mid+1,r);
	//pushup(wh);
}
inline aa work(int wh,int wl,int wr){
	if(wl<=t[wh].l&&t[wh].r<=wr)return t[wh].data;
	pushdown(wh);
	if(wl<=mid&&wr>mid)return work(lc,wl,wr)+work(rc,wl,wr);
	else if(wl<=mid)return work(lc,wl,wr);
	else if(wr>mid)return work(rc,wl,wr);
	//printf("work:%d %d %d\n",wh,wl,wr);
	//print(an);
}
inline void change(int wh,int wl,int wr,int val){
	if(wl<=t[wh].l&&t[wh].r<=wr){
		pushnow(wh,val);return;
	}
	pushdown(wh);
	if(wl<=mid)change(lc,wl,wr,val);
	if(wr>mid)change(rc,wl,wr,val);
	pushup(wh);return;
}
#undef lc
#undef rc
#undef mid

struct edge{
	int t,next;
}e[N<<1];
int head[N],esum;
inline void add(int fr,int to){
	e[++esum]=(edge){to,head[fr]};head[fr]=esum;
}

int m,n;

int size[N],son[N],lg[N],d[N],nxt[N][25];
void dfs(int wh,int fa,int deep){
	size[wh]=1;d[wh]=deep;nxt[wh][0]=fa;
	for(int i=1;i<=lg[d[wh]];i++)nxt[wh][i]=nxt[nxt[wh][i-1]][i-1];
	for(int i=head[wh],th;i;i=e[i].next){
		if((th=e[i].t)==fa)continue;
		dfs(th,wh,deep+1);size[wh]+=size[th];
		if(size[th]>size[son[wh]])son[wh]=th;
	}
}

inline int lca(int s1,int s2){
	if(d[s1]<d[s2])swap(s1,s2);
	for(int i=lg[d[s1]];i>=0;i--){
		if(d[nxt[s1][i]]>=d[s2]){
			s1=nxt[s1][i];
		}
	}
	if(s1==s2)return s1;
	for(int i=lg[d[s1]];i>=0;i--){
		if(nxt[s1][i]^nxt[s2][i]){
			s1=nxt[s1][i],s2=nxt[s2][i];
		}
	}
	return nxt[s1][0];
}

int cnt,top[N],id[N];
void dfs2(int wh,int ntop,int fa){
	top[wh]=ntop;id[wh]=++cnt;
	if(son[wh])dfs2(son[wh],ntop,wh);
	for(int i=head[wh],th;i;i=e[i].next){
		if((th=e[i].t)==fa)continue;if(th==son[wh])continue;
		dfs2(th,th,wh);
	}
}

void solve(){
	esum=cnt=0;
	memset(head,0,sizeof(head));
	memset(size,0,sizeof(size));
	memset(son,0,sizeof(son));
	memset(nxt,0,sizeof(nxt));
	memset(d,0,sizeof(d));
	memset(top,0,sizeof(top));
	memset(id,0,sizeof(id));
	
	read(m);read(n);int s1,s2,color=m+1;
	for(int i=1;i<m;i++){
		read(s1);read(s2);
		add(s1,s2);add(s2,s1);
	}
	dfs(1,0,1);dfs2(1,1,0);
	build(1,1,m);
	//for(int i=1;i<=m;i++)printf("%d\n",id[i]);
	while(n--){
		int op,a,b;read(op);read(a);read(b);int ll=lca(a,b);
		if(op==1){
			color++;
			while(top[a]^top[b]){
				if(d[top[a]]<d[top[b]])swap(a,b);
				change(1,id[top[a]],id[a],color);
				a=nxt[top[a]][0];
			}
			if(d[a]<d[b])swap(a,b);
			change(1,id[b],id[a],color);
		}
		else{
			aa ana={0,0,0},anb={0,0,0};
			while(top[a]^top[b]){
				if(d[top[a]]<d[top[b]])swap(a,b),swap_aa(ana,anb);
				ana=work(1,id[top[a]],id[a])+ana;
				a=nxt[top[a]][0];
			}
			if(d[a]<d[b])swap(a,b),swap_aa(ana,anb);
			ana=work(1,id[b],id[a])+ana;
			printf("%d\n",ana.data+anb.data+(ana.lc==anb.lc&&ana.lc!=0));
		}
		//color++;
	}
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	#endif
	
	lg[0]=1;
	for(int i=1;i<N;i++)lg[i]=lg[i>>1]+1;
	int T;read(T);
	while(T--){
		solve();
	}
	
	return 0;
}
posted @ 2022-07-04 17:17  Feyn618  阅读(21)  评论(0编辑  收藏  举报