首页 > 其他分享 >[JOISC 2023 Day3] Tourism 题解

[JOISC 2023 Day3] Tourism 题解

时间:2024-08-21 20:37:28浏览次数:12  
标签:int 题解 tp 朵莉树 JOISC dfn sn Tourism 虚树

大家好,我喜欢珂朵莉树,所以我用珂朵莉树 \(AC\) 了本题。


实际上,我们比较容易发现,这题实际上就是求 \([l,r]\) 中的所有点作为关键点时,虚树所压缩的所有点(实际上就是显现出来的点+在虚边上的点)。

那么我们容易发现,一个点 \(x\) 作为虚树所压缩的所有点的充要条件为:

  1. \(x\) 是至少一个虚树关键点的祖先。
  2. \(x\) 子树外至少有一个虚树关键点。

不易发现这里可以容斥。\((1+2)=(1all)-(1+!2)\)。


\((1+!2)\),即满足 \(1\),不满足 \(2\) 的情况。我们发现 \(lca(a_l,a_{l+1}...,a_r)\) 的所有祖先都满足这种情况,当然,也只有他们满足这种情况。

我们知道 \(lca(a_l,a_{l+1}...,a_r)=lca(a_x,a_y)\),其中 \(dfn_x=\max\limits_{i=l}^r dfn_i,dfn_y=\min\limits_{i=l}^r dfn_i\)。\(x,y\) 可以用 \(ST\) 表维护。

这一部分时间复杂度为 \(O(n\log n)\)。


\((1all)\),即满足 \(1\),不考虑 \(2\) 的情况。这里就比较难处理了。

我们设 \(col_{i,j}\) 表示当询问区间的 \(r\) 为 \(j\) 时,\(i\) 子树内所有虚树关键点中最大的下标。

当 \(r\) 右移至 \(r+1\) 时,路径 \((1,r+1)\) 上所有点的答案都会变成 \(r+1\)。

相当于问题就变成:维护一个数据结构,可以实现树链染色。

树链数量越少越好,可以想到重链剖分,问题变为区间染色。

区间染色?区间推平?珂朵莉树!我们用树剖+珂朵莉树来进行区间染色。

考虑如何统计答案。

本人实测,不能遍历珂朵莉树中所有块来维护答案。考虑使用 \(BIT\) 维护颜色个数前缀和。

时间复杂度瓶颈在于树剖+珂朵莉树,时间复杂度 \(O(n\log^2 n)\)。


总结一下,时间复杂度为 \(O(n\log^2n)\)。

//中国珂学院 SNGXYZ 分院 OI 科第三办公室研究员 LYH
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,m,q,id,pos[N];
int a[N],ans[N];
vector<int>g[N];
int sz[N],tp[N];
int dfn[N],fa[N];
int sn[N],dep[N];
int sd[2][N][18];
void st_biao(){
	for(int i=1;i<=m;i++)
		sd[0][i][0]=sd[1][i][0]=dfn[a[i]];
	for(int i=0;i<17;i++)
		for(int j=1;j<=m-(1<<i);j++){
			sd[0][j][i+1]=max(sd[0][j][i],sd[0][j+(1<<i)][i]);
			sd[1][j][i+1]=min(sd[1][j][i],sd[1][j+(1<<i)][i]);
		}
}int rmq(int l,int r,int opt){
	int k=log2(r-l+1),x=r-(1<<k)+1;
	if(opt) return min(sd[1][l][k],sd[1][x][k]);
	return max(sd[0][l][k],sd[0][x][k]);
}struct que{
	int l,r,id;
}qu[N];
int cmp(que x,que y){
	return x.r<y.r;
}struct BIT{
	int c[N];
	void add(int x,int y){
		for(;x<=m+1;x+=x&-x)
			c[x]+=y;
	}int sum(int x){
		int re=0;
		for(;x;x-=x&-x)
			re+=c[x];
		return re;
	}
}bit;
struct odt{
	int l,r;
	mutable int v;
	bool operator<(const odt &c)const{
		return l<c.l;
	}
};set<odt>st;
#define iter set<odt>::iterator
struct chtholly{
	iter spilt(int x){
		iter it=st.lower_bound({x,0,0});
		if(it!=st.end()&&(*it).l==x) return it;
		it--;if((*it).r<x) return st.end();
		int l=(*it).l,r=(*it).r,v=(*it).v;
		st.erase(it);
        if(x!=l) st.insert({l,x-1,v});
		return st.insert({x,r,v}).first;
	}void assign(int l,int r,int v){
		iter tr=spilt(r+1),tl=spilt(l);
		for(iter it=tl;it!=tr;it++)
			bit.add((*it).v+1,(*it).l-(*it).r-1);
		bit.add(v+1,r-l+1);
		st.erase(tl,tr);st.insert({l,r,v});
	}
}seniorious;
void dfs1(int x,int f){
	dep[x]=dep[f]+1;
	for(auto y:g[x]){
		if(y==f) continue;
		dfs1(y,x);sz[x]+=sz[y];
		if(sz[y]>sz[sn[x]]) sn[x]=y;
	}fa[x]=f,sz[x]++;
}void dfs2(int x,int top){
	dfn[x]=++id;
	tp[x]=top;pos[id]=x;
	if(!sn[x]) return;
	dfs2(sn[x],top);
	for(auto y:g[x])
		if(y!=fa[x]&&y!=sn[x])
			dfs2(y,y);
}int lca(int x,int y){
	while(tp[x]!=tp[y]){
		if(dep[tp[x]]<dep[tp[y]]) y=fa[tp[y]];
		else x=fa[tp[x]];
	}return dep[x]<dep[y]?x:y;
}void col(int x,int c){
	while(x) seniorious.assign(dfn[tp[x]],dfn[x],c),x=fa[tp[x]];
}int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>m>>q;
	for(int i=1;i<n;i++){
		int x,y;cin>>x>>y;
		g[x].push_back(y);
		g[y].push_back(x);
	}dfs1(1,0);dfs2(1,1);
	for(int i=1;i<=m;i++) cin>>a[i];
	int now=1;st_biao();
	for(int i=1;i<=q;i++)
		cin>>qu[i].l>>qu[i].r,qu[i].id=i;
	sort(qu+1,qu+q+1,cmp);
	st.insert({1,n,0});
	bit.add(1,n);
	for(int i=1;i<=q;i++){
		while(now<=qu[i].r) col(a[now],now),now++;
		ans[qu[i].id]=bit.sum(qu[i].r+1)-bit.sum(qu[i].l);
		int mn=pos[rmq(qu[i].l,qu[i].r,1)];
		int mx=pos[rmq(qu[i].l,qu[i].r,0)];
		ans[qu[i].id]-=dep[lca(mn,mx)]-1;
	}for(int i=1;i<=q;i++)
		cout<<ans[i]<<"\n";
	return 0;
}/*Kaká
在太阳西斜的这个世界里,置身天上之森。
等这场战争结束之后,不归之人与望眼欲穿的众人。
人人本着正义之名,长存不灭的过去、逐渐消逝的未来。
我回来了,纵使日薄西山,即便看不到未来。
此时此刻的光辉,盼君勿忘。
————世界上最幸福的女孩
(珂朵莉树lyh专用标识)
*/

标签:int,题解,tp,朵莉树,JOISC,dfn,sn,Tourism,虚树
From: https://www.cnblogs.com/chang-an-22-lyh/p/18372478/joisc2023day3-tourism-tj

相关文章

  • 【题解】Solution Set - NOIP2024集训Day12 树上启发式合并
    【题解】SolutionSet-NOIP2024集训Day12树上启发式合并https://www.becoder.com.cn/contest/5472「CF600E」Lomsatgelral直接dsuontree。记录每一个颜色的出现次数。「IOI2011」Race之前是用点分治做的。考虑dsuontree。每个子树内维护到根节点的距离为\(x\)......
  • SP368 CSTREET - Cobbled streets 题解
    题意选n−1条道路连接n个城市,且使得其修建的价格最小。分析最小生成树的模板题,可以用kruskal来做。首先,先将所有的边权从小到大排序。然后,取当前没有选过的,且边权最小的边,判断它连接的两个点是否同属一个集合,如果不是就把他们加到同一个集合中,再记录答案。代码很简单,......
  • 莫队的 1.5 近似构造 题解
    前言题目链接:洛谷。感觉T4比T3水,虽然我都没做出来。题意简述给定\(1\simn\)的排列\(a\)和\(m\)个区间\([l_i,r_i]\)。定义值域区间\([L,R]\)的价值为\(\operatorname{val}([L,R])\operatorname{:=}\max\limits_{i=1}^m\sum\limits_{k=l_i}^{r_i}[L......
  • P10892 SDOI2024 题解
    【题意简述】你有一个数字\(n\),每次操作将\(n/2\),如果\(n\)是一个奇数,你会纠结是向上取整还是向下取整。问你最少纠结多少次。多组数据。【思路】为了方便起见,我们在二进制下重新审视这个题目:在二进制下,一个数除以\(2\)等同于右移一位。默认向下取整,因为右移会舍弃......
  • P7706 文文的摄影布置 题解
    P7706文文的摄影布置题解原题读完题,发现是线段树。单点修改+区间查询。不过查询的值有些奇怪,就是了,我们考虑用线段树维护这个ψ值(下称待求值)。对于一个区间的待求值,大概有四种情况:如上图四种情况分别为:待求值最大值在左区间待求值最大值在右区间\(a_i与b_j\)在左......
  • 一元柯西问题解法整理与试证明(傅里叶变换的应用)
    关于柯西问题:  柯西问题是指偏微分方程仅有初始条件而无边界条件的定解问题,常用特征线法、分离变量法、格林函数法以及傅里叶变换求解,柯西问题即对于  其中   为主函数, 为初始条件,求解U(x,t)关于傅里叶变换:公式:对于一维方程f(x)有    或  卷积:若,则......
  • [题解]P2444 [POI2000] 病毒
    P2444[POI2000]病毒题目核心是多模式匹配,所以考虑用对所有模式串建立AC自动机。我们把自动机上,存在一个模式串作为前缀的节点,称作“危险节点”。如果无限长的安全代码存在的话,匹配过程中Trie图上一定有节点会经过多次,即存在环;而且经过的所有节点都不是“危险节点”,否则就包含......
  • TCP通信之经典问题解决
    先看下面的代码,研究下执行后会出现什么?服务端:fromsocketimport*ip_port=('127.0.0.1',8003)buffer_size=1024sock_server=socket(AF_INET,SOCK_STREAM)sock_server.bind(ip_port)sock_server.listen(5)whileTrue:print('服务端建立连接...')conn,addr=soc......
  • P1972 [SDOI2009] HH的项链 题解
    前言这是一篇分块题解,大概的思路洛谷的题解里的巨佬讲的很清楚(我的思路其实和大佬的差不多),可以去看看qaq。因为苯人为了卡常魔改代码,所以在本题解的中间具体步骤展示部分仅展示魔改前的代码(也就是被卡常但是好看一点的代码),魔改后的代码(100pts)在文章最末展示。题意题面传送门......
  • 操作系统基础之磁盘及软考高级试题解析
    概述基本概念磁盘有正反两个盘面,每个盘面有多个同心圆,每个同心圆是一个磁道,每个同心圆又被划分为多个扇区,数据就被存在扇区中。磁头首先寻找到对应磁道,然后等到磁盘进行周期旋转到指定的扇区,才能读取到对应的数据。存取时间=寻道时间+等待时间盘面号(磁头号):0~M-1;由于一......