首页 > 其他分享 >【Ynoi2009】 rla1rmdq 题解 (离线分块 + 线性空复处理)

【Ynoi2009】 rla1rmdq 题解 (离线分块 + 线性空复处理)

时间:2022-10-04 19:57:26浏览次数:93  
标签:空复 val 题解 rep anss 离线 tag que 节点

洛谷传送门

分块。

Solution

看到是区修区查,还有时限,不难想到是分块,根号复杂度。

然后看到空间复杂度,需要离线下来转为线性复杂度。


考虑如何分块。观察操作性质,发现节点深度越大对答案的贡献就越小,即,若一个点将要跳的祖先已经在区间里出现过了,那它目前就没有意义了。这启发我们实时维护这些“有意义的节点”,每次整块修改的时候只需要跳这些节点即可。

但是散块的修改可能会让曾经“无意义”的节点变为“有意义的”——它可能单独跳很多,这样就变为有意义的了。为了让这些无意义节点还能往上跳祖先,我们还需要维护一个 \(tag\),表示整块处理了几次,即让当前所有有意义节点一起向上跳父亲跳了几次。不妨思考,一个无意义节点和有意义节点的差别是什么?就是它在变为无意义节点之后,其他有意义节点跳父亲时,它没有参与。那现在我想让它变为有意义节点,只需要把它“错过”的几次跳父亲操作补回来就可以了。所以在 \(tag\) 的基础上,我们对于每个节点 \(i\),还要维护 \(val_i\),表示它参与了几次整块处理时所有有意义节点进行的跳父亲操作。那么现在,对于散块中的一个节点,我只需要让它向上跳 \(tag - val_i+1\) 次父亲即可完成修改——其中 \(+1\) 是当前对它的修改,\(tag-val_i\) 是它错过的修改。跳完之后,再看它是否变为有意义节点,如果是,那么把它扔进序列中、打标记,维护即可。


查询的话,因为是离线对每个块单独处理,所以我们可以实时维护整块的答案;对于散块,按照散块修改时的方式让散块的节点单独跳祖先,对于每个节点单独统计贡献即可。


维护/跳祖先的话,直接使用重链剖分即可,不影响复杂度。

总时复 \(\mathcal{\text{O}}(n\sqrt n)\)。

Code

#include<bits/stdc++.h>
using namespace std;

#define ll long long 
#define rep(i, a, b) for(register int i = a; i <= b; ++i)
#define go(u) for(int i = hd[u], v = e[i].to; i; i = e[i].nxt, v = e[i].to)
const int maxn = 2e5 + 5;
int n, m, rt;
struct que{
	int opt, l, r;
}q[maxn]; ll dep[maxn], ans[maxn];
int cnt, hd[maxn];
struct node{
	int to, nxt, w;
}e[maxn << 1];
int fa[maxn], siz[maxn], mxs[maxn];
int dp[maxn], tp[maxn], dfn[maxn], tot, idfn[maxn];
bool vis[maxn], inq[maxn];
int a[maxn], que[maxn], top, val[maxn], tag;

inline void add(int u, int v, int w){
	e[++cnt] = (node){v, hd[u], w}; hd[u] = cnt;
}

inline void dfs1(int u, int f){
	dp[u] = dp[fa[u] = f] + 1, siz[u] = 1; 
	go(u) if(v ^ f){
		dep[v] = dep[u] + e[i].w, dfs1(v, u);
		if(siz[mxs[u]] < siz[v]) mxs[u] = v;
		siz[u] += siz[v];
	}
}

inline void dfs2(int u, int anc){
	tp[u] = anc, dfn[u] = ++tot, idfn[tot] = u;
	if(!mxs[u]) return; dfs2(mxs[u], anc);
	go(u) if(v != fa[u] and v != mxs[u])
		dfs2(v, v);
}

inline int kth(int x, int k){ 
	if(k >= dp[x]) return rt;
	while(k >= dp[x] - dp[tp[x]] + 1)
		k -= dp[x] - dp[tp[x]] + 1, x = fa[tp[x]];
	return idfn[dfn[x] - k];
}

inline void slv(int L, int R){ 
	tag = top = 0; ll anss = 1e18;
	rep(i, 1, n) vis[i] = inq[i] = que[i] = val[i] = 0;
	rep(i, L, R) if(!vis[a[i]])
		que[++top] = i, inq[i] = 1, vis[a[i]] = 1, anss = min(anss, dep[a[i]]);
	rep(i, 1, m){ int l = max(L, q[i].l), r = min(R, q[i].r);
		if(l > r) continue;
		if(q[i].opt == 1)
			if(l == L and r == R){ tag += 1; int tmp = top; top = 0;
				rep(j, 1, tmp){ val[que[j]] += 1;
					if(vis[a[que[j]] = fa[a[que[j]]]]) inq[que[j]] = 0;
					else que[++top] = que[j], vis[a[que[j]]] = 1, 
						anss = min(anss, dep[a[que[j]]]);
				}
			} else rep(j, l, r){
				if(!vis[a[j] = kth(a[j], tag - val[j] + 1)]){
					anss = min(anss, dep[a[j]]), vis[a[j]] = 1;
					if(!inq[j]) que[++top] = j, inq[j] = 1;
				} val[j] = tag;
			}
		else{ if(l == L and r == R) ans[i] = min(ans[i], anss);
			else rep(j, l, r) 
					ans[i] = min(ans[i], dep[a[j] = kth(a[j], tag - val[j])]), val[j] = tag; 
		}
	} 
}

signed main(){ int len;
	scanf("%d%d%d", &n, &m, &rt); len = sqrt(n);
	rep(i, 2, n){ int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		add(u, v, w), add(v, u, w);
	} dfs1(rt, rt), dfs2(rt, rt);
	rep(i, 1, n) scanf("%d", &a[i]);
	rep(i, 1, m) ans[i] = 1e18,
		scanf("%d%d%d", &q[i].opt, &q[i].l, &q[i].r);
	for(int i = 1; i <= n; i += len)
 		slv(i, min(i + len - 1, n));
 	rep(i, 1, m) if(q[i].opt == 2) printf("%lld\n", ans[i]);
	return 0;
}

感谢阅读。

标签:空复,val,题解,rep,anss,离线,tag,que,节点
From: https://www.cnblogs.com/gsn531/p/16754309.html

相关文章

  • 「CF1455G」Forbidden Value 题解 (DP,线段树合并)
    题目简介已知初始值\(x=0\),给定下面\(2\)种命令:set\(y\)\(v\),令\(x=y\),或花费\(v\)元钱删除该命令;if\(y\)...end,如果\(x==y\),执行if...end中的命令,否则跳......
  • [题解]洛谷 P4930、BZOJ 4221
    洛谷P4930考虑\(\varphi\)有什么性质,设\(x\)的质因数分解为\(\prod_{i=1}^mp_i^{a_i}\),那么\(n=\varphi(x)=\prod_{i=1}^m(p_i-1)\times\prod_{i=1}^mp_i^{a_i-1......
  • python在没有公网的情况下pip安装离线包
    首要条件是找一台可以连接公网的服务器。1、生成requirements.txtpip3freeze>requirements.txt2、创建本地仓库repodatamkdir./repodata3、拉取离线whl包pi......
  • 「ROIR 2021 Day 1」题解
    loj有原题。别问为什么没T4,问就是不会,等以后来补。T1-两台机器设两台机子分别为\(a,b\),分\(4\)种情况:只用\(a\),只用\(b\),先\(a\)后\(b\),先\(b\)后\(a\),判断......
  • 0464-如何离线分析HDFS的FsImage查找集群小文件
    温馨提示:如果使用电脑查看图片不清晰,可以使用手机打开文章单击文中的图片放大查看高清原图。Fayson的github:​​https://github.com/fayson/cdhproject​​提示:代码块部分可......
  • Windows下CLion中文乱码问题解决
    (目录)原因分析Windows内部采用UTF-16编码,对于中文操作系统使用GBK编码,但是CLion默认文本编码为UTF-8,当编码不一致时,就会造成输出乱码,甚至编译不通过。解决方案当然,对于......
  • 类与对象课件问题解答
    结果:true 结果:false原因:当“==”施加于原始数据类型变量时,是比较变量所保存的数据是否相等。     当“==”施加于引用类型变量时,是比较这两个变量是否引用......
  • Luogu P5089 [eJOI2018] 元素周期表 题解
    (从洛谷博客搬过来的)这道题嘛..主要还是找性质推规律。拿到题,第一眼:噢噢爆搜啊。第二眼:噢噢贪心啊。第三眼:很好贪心假了。然后苦思冥想半个小时去看题解。看到兔队的......
  • CF1427E Xum 题解
    (从洛谷博客搬过来的)学校比赛的时候考了这道题,我当然是一分没得。这是一道好构造题。先不说正解,我看别的题解都没有说怎么拿部分分,但是如果赛时不会正解,那么拿部分分就......
  • “科林明伦杯”哈尔滨理工大学暑假训练赛 F 题解
    题目内容传送门前置知识组合数乘法逆元Modularint模板题目分析分析输入与题意,本题关键即在推导有多少个不同数组的计算公式。设当前数组最大值为i,则有:\[ans_i......