首页 > 其他分享 >[NOI2021] 轻重边题解

[NOI2021] 轻重边题解

时间:2023-09-02 09:22:05浏览次数:44  
标签:dep 题解 ll top tr id NOI2021 wz 轻重

题目传送门

一眼数据结构

考虑树上有什么数据结构支持 \(x\) 到 \(y\) 节点的修改和查询,那就是:树链剖分。

那么这道树链剖分的题有个 \(trick\):边点转换&染色法,对于每次修改,考虑将修改路径上的点全部染上一种独一无二的颜色,而查询的时候,就查询路径上相邻的相同的颜色节点个数即可。

正确性易证:因为每次修改,该点周围的边都变成轻边除了那条路径上的边,因为那条路径上的点必然与该点颜色一样,而不是路径上的点必然与该点颜色不一样,所以可以转换成求路径上相邻的相同的颜色节点个数。

考虑怎么求:对于线段树上的点,开一个结构体,记 \(lc:\) 该区间左端点颜色,\(rc:\) 该区间右端点颜色,\(gs:\) 该区间相邻相同颜色节点个数,\(tag:\) 懒标记(要区间修改)

一些小细节:

\(1\),初始化时把所有数组都初始化了,防止出现神奇错误(比如我为此调了半小时),不差这点常数。

\(2\),要特别注意 \(top_x=top_y\) 的情况,大部分错误都出现在这里。

上代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=1e5+50;
ll T,n,m,u,v;
vector<ll> e[N];
ll dep[N],fa[N],siz[N],son[N];
void dfs1(ll wz,ll last)
{
	dep[wz]=dep[last]+1;
	fa[wz]=last;
	siz[wz]=1;
	ll bigson=0;
	for(ll i=0;i<e[wz].size();i++)
	{
		ll j=e[wz][i];
		if(j==last) continue;
		dfs1(j,wz);
		siz[wz]+=siz[j];
		if(siz[j]>bigson) bigson=siz[j],son[wz]=j;
	}
}
ll top[N],id[N],cnt;
void dfs2(ll wz,ll topf)
{
	top[wz]=topf;
	id[wz]=++cnt;
	if(!son[wz]) return ;
	dfs2(son[wz],topf);
	for(ll i=0;i<e[wz].size();i++)
	{
		ll j=e[wz][i];
		if(j==fa[wz]||j==son[wz]) continue;
		dfs2(j,j);
	}
}
struct jgt
{
	ll lc,rc,gs,tag;
}tr[N*8];
ll idx;
void pushup(jgt &wz,jgt l,jgt r)
{
	wz.gs=l.gs+r.gs+(l.rc==r.lc);
	wz.rc=r.rc;
	wz.lc=l.lc;
}
void BT(ll wz,ll l,ll r)
{
	if(l==r)
	{
		tr[wz].lc=l;
		tr[wz].rc=l;
		tr[wz].gs=0;
		tr[wz].tag=0;
		return ;
	}
	ll mid=(l+r)/2;
	BT(wz*2,l,mid);
	BT(wz*2+1,mid+1,r);
	pushup(tr[wz],tr[wz*2],tr[wz*2+1]);
}
void pushdown(ll wz,ll l,ll r)
{
	ll mid=(l+r)/2;
	tr[wz*2].gs=mid-l;
	tr[wz*2].rc=tr[wz].tag;
	tr[wz*2].lc=tr[wz].tag;
	tr[wz*2].tag=tr[wz].tag;
	tr[wz*2+1].gs=r-mid-1; 
	tr[wz*2+1].rc=tr[wz].tag;
	tr[wz*2+1].lc=tr[wz].tag;
	tr[wz*2+1].tag=tr[wz].tag;
	tr[wz].tag=0;
}
void gai(ll wz,ll l,ll r,ll le,ll ri,ll co)
{
	if(le<=l&&ri>=r)
	{
		tr[wz].gs=r-l;
		tr[wz].rc=co;
		tr[wz].lc=co;
		tr[wz].tag=co;
		return ;
	}
	if(tr[wz].tag&&l!=r) pushdown(wz,l,r);
	ll mid=(l+r)/2;
	if(le<=mid) gai(wz*2,l,mid,le,ri,co);
	if(ri>mid) gai(wz*2+1,mid+1,r,le,ri,co);
	pushup(tr[wz],tr[wz*2],tr[wz*2+1]);
}
jgt query(ll wz,ll l,ll r,ll le,ll ri)
{
	if(le<=l&&ri>=r) return tr[wz];
	if(tr[wz].tag&&l!=r) pushdown(wz,l,r);
	ll mid=(l+r)/2;
	if(le<=mid&&ri>mid)
	{
		jgt t1=query(wz*2,l,mid,le,ri);
		jgt t2=query(wz*2+1,mid+1,r,le,ri);
		jgt t3;
		pushup(t3,t1,t2);
		return t3;
	} 
	if(le<=mid) return query(wz*2,l,mid,le,ri);
	if(ri>mid) return query(wz*2+1,mid+1,r,le,ri);
}
void upd(ll x,ll y,ll co)
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		gai(1,1,n,id[top[x]],id[x],co);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	gai(1,1,n,id[x],id[y],co);
}
ll updQ(ll x,ll y)
{
	ll ans1=0,ans2=0,co1=0,co2=0,w=0;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y),w^=1;
		jgt tzy=query(1,1,n,id[top[x]],id[x]);
		if(w==1)
		{
			ans2=ans2+tzy.gs+(tzy.rc==co2);
			co2=tzy.lc;
		}
		else
		{
			ans1=ans1+tzy.gs+(tzy.rc==co1);
			co1=tzy.lc;
		}
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y),w^=1;
	jgt tzy=query(1,1,n,id[x],id[y]);
	if(w==0)
		return (ans1+ans2+tzy.gs+(tzy.lc==co1)+(tzy.rc==co2));
	else
		return (ans1+ans2+tzy.gs+(tzy.lc==co2)+(tzy.rc==co1));
}
void Init()
{
	cnt=0,idx=0;
	memset(son,0,sizeof son);
	memset(fa,0,sizeof fa);
	memset(siz,0,sizeof siz);
	memset(dep,0,sizeof dep);
	memset(top,0,sizeof top);
	memset(id,0,sizeof id);
	memset(tr,0,sizeof tr);
	for(ll i=1;i<=n;i++) e[i].clear(); 
}
int main()
{
	scanf("%lld",&T);
	while(T--)
	{
		scanf("%lld %lld",&n,&m);
		for(ll i=1;i<n;i++)
		{
			scanf("%lld %lld",&u,&v);
			e[u].push_back(v);
			e[v].push_back(u);
		}
		dfs1(1,0);
		dfs2(1,1);
		BT(1,1,n);
		idx=n;
		ll opt,x,y;
		for(ll i=1;i<=m;i++)
		{
			scanf("%lld %lld %lld",&opt,&x,&y);
			if(opt==1) upd(x,y,++idx);
			if(opt==2) printf("%lld\n",updQ(x,y));
		}
		Init();
	}
	return 0;
}

标签:dep,题解,ll,top,tr,id,NOI2021,wz,轻重
From: https://www.cnblogs.com/pengchujie/p/17673206.html

相关文章

  • 爱思创模拟06试题易错题解析
    错误原因:漏项正确答案:C按节点数分类穷举 举一反三:  错误原因:处理三个空位的时候,情况考虑的太多正确答案:分情况计算,先枚举4个人共A(4,4)=24种情况,再考虑剩下两个空位置的情况,即A(5,2)=20种情况,最终答案就是24*20=480种举一反三:  错误原因:不会计算时间复杂度......
  • 题解 正妹吃月饼
    题目链接由于每个质量的月饼只有一个,并且质量恰好是2的整数倍,所以考虑将一个质量看成一个二进制位。那么也就是说,我们要构造一个二进制数\(x\),使得\(x\)的\(1\)的个数最多,且满足\(a\lex\leb\)。那么这就可以用类似数位\(DP\)的思路来做,从高位往低位看,若\(a_i=b_i=1......
  • NOIP2012提高组初赛易错题解析
    一.3. 错误原因:忘记了解析:Intel是全球最大的CPU厂商,AMD是世界上首个研发出7纳米CPU的厂商 6.错误原因:忘记了解析:ENIAC是世界上首台计算机,属于第一代计算机,即电子管计算机 10.错误原因:选项理解错误解析:A由蝙蝠,发明雷达是正确的,B因特网的发明与蜘蛛网无关,只是形......
  • NOIP2011提高组初赛易错题解析
    一.7.错误原因:不知道解析:快速排序在理论上最低的时间复杂度为O(n),但实际最低的时间复杂度为O(nlogn) 二.1.错误原因:漏项了解析:这棵树最少有12层,但题目是问可能是几层,所以还可能是2011层 5.错误原因:漏了一种情况解析:这道题的树有两种,所以答案也有两种 ......
  • 牛客小白月赛77 C题解 | 小Why的商品归位
    原题链接先不考虑车子的容量问题,因为结束位置保证是在起始位置之后的,那我们从前往后扫,发现是可以知道每个点时的车内的商品。但是现在有了容量限制,我们怎么办呢,如果对于一段,k都是大于每个点的货物量时,可以一趟装完,但是如果大于k就需要不知一次,可以发现所需的其实是该段的最大......
  • CF1626F A Random Code Problem 题解
    题意给定长度为\(n\)的数组\(a\)和一个整数\(k\),执行下面的代码:longlongans=0;//定义一个初始值为0的长整型变量for(inti=1;i<=k;i++){ intidx=rnd.next(0,n-1);//生成一个介于0到n-1的随机数(含0和n-1) //每个数被选中的概率是相同的 an......
  • Maximum Diameter 题解
    MaximumDiameter题目大意定义长度为\(n\)的序列\(a\)的权值为:所有的\(n\)个点的第\(i\)个点的度数为\(a_i\)的树的直径最大值,如果不存在这样的树,其权值为\(0\)。给定\(n\),求所有长度为\(n\)的序列的权值和。思路分析\(n\)个点的树的边数为\(n-1\),总度数......
  • 【题解】Harbour.Space Scholarship Contest 2023-2024 D,E,F(CF1864)
    D.MatrixCascade题目描述:有一个大小为\(n\timesn\)的矩阵,由0和1组成。行的编号从上到下依次为\(1\)到\(n\),列的编号从左到右依次为\(1\)到\(n\)。第\(x\)行与第\(y\)列交叉处的单元格记为\((x,y)\)。水月想把矩阵的所有元素都变成0。她可以一步完成以下操作:选择任意......
  • kde桌面“屏幕边缘”无法触发问题解决
    鼠标放到屏幕边缘无法触发效果,搜索后是设置问题。解决办法:系统设置——硬件——显卡与显示器——显示特效合成器,勾选允许应用阻止显示特效合成,然后右下角点击应用参考:https://www.cnblogs.com/pipci/p/14870650.html......
  • CF1864D 题解
    CF1864DMatrixCascade题解Links洛谷CodeforcesDescription给定一个\(n\timesn\)的01矩阵。定义一次操作为:选择矩阵上第\(i\)行第\(j\)列的格子\((i,j)\),将其取反,并取反所有满足\(x>i,x-i\ge|y-j|\)的位置\((x,y)\)。其中,“取反”的意思为:把\(0\)......