首页 > 其他分享 >CF757G Can Bash Save the Day? (复健 Day 1)

CF757G Can Bash Save the Day? (复健 Day 1)

时间:2023-01-07 21:11:06浏览次数:43  
标签:复健 include int tr CF757G sn cp Day

先差分为 \(Q(r)-Q(l-1)\),\(Q(i)=\sum_{j=1}^{i} \operatorname{dis}(p_j, x)\)。

树上在线路径优先考虑点分树,先想询问怎么做,我们记 \(f_i\) 为点分树上 \(i\) 点子树内所有前缀的 \(p\) 点到 \(i\) 的距离和,并记录 \(g_i\) 为 \(i\) 子树内的 \(p_i\) 点到 \(fa_i\) 的距离,\(h_i\) 为 \(i\) 子树内 \(p\) 点的个数,那么对于每次询问,我们在点分树上跳,点 \(j\) 的父亲 \(i\) 贡献即为 \((f_i-g_j)+(h_i-h_j)\times\operatorname{dis}(i, x)\)(\(j\) 是 \(x\) 到根路径上的点,特别地,\(i=x\) 的时候关于 \(j\) 的值视为 0 即可),用 \(O(1) \operatorname{LCA}\) 能做到 \(O(\log n)\) 处理查询。

那么加入一个点的贡献时,我们只需快速维护 \(f, g, h\) 即可,点分树深度为 \(\log n\),因此可以直接暴力修改。

交换操作就是对 \(x\) 处的前缀修改,因此我们要做的就是可持久化一个数组,直接主席树的话空间 $O((n+m)\log^2) $ 有点紧,不知道能不能过。

思考一下本质,为什么我们无法绕过主席树?我们每次操作只会修改一条到根的链的结点,但是可持久化需要保留所有儿子的信息,一次暴力复制的时空复杂度都可以很轻松的卡到 \(O(n)\) 级别,我们需要操作的就是将儿子的信息尽量简化,由此便可以联想到边分治中的三度化,不过注意此时应该是原树三度化后再点分树,否则会失去原来 \(\log\) 层的特性。

Code:

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <cctype>
#include <vector>
#include <queue>
#include <bitset> 
#define pb push_back
#define mp make_pair
#define st first
#define nd second
using namespace std;
typedef long long ll;
typedef pair <int, int> Pii;
const int INF=0x3f3f3f3f;
const int cp=1<<30;
inline int plust(int x, int y){x+=y;if(x>=cp) x-=cp;if(x<0) x+=cp;return x;}
inline int minut(int x, int y){x-=y;if(x>=cp) x-=cp;if(x<0) x+=cp;return x;}
inline int read(){
	char ch=getchar();int x=0, f=1;
	while(!isdigit(ch)){if(ch=='-') f=-1; ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x){
    if(x<0) putchar('-'), x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
inline int ksm(int a, int b=cp-2){
	int ret=1;
	for(; b; b>>=1, a=1ll*a*a%cp)
		if(b&1) ret=1ll*ret*a%cp;
	return ret;
}
const int N=2e5+5;
int n, m, p[N], ecnt, cnt, ROOT, Rt, sMn, ndc, tot, tim;
int h[N], vis[N<<1], dep[N<<1], siz[N<<1];
int in[N<<1], fa[N<<1], lg[N<<2], ST[N<<2][21], rt[N];
ll dis[N<<1];
struct Edge{int to, nxt, w;}d[N<<1];
void add(int x, int y, int z){d[++ecnt]=(Edge){y, h[x], z};h[x]=ecnt;}
vector <Pii> G[N<<1];
struct node{int id, sn[3], h;ll f, g;}tr[N*70];
int Mx(int x, int y){return dep[x]<dep[y]?x:y;}
int LCA(int x, int y){
	x=in[x], y=in[y];if(x>y) swap(x, y);
	int k=lg[y-x+1];return Mx(ST[x][k], ST[y-(1<<k)+1][k]);
}
ll dist(int x, int y){if(!x||!y) return 0;return dis[x]+dis[y]-dis[LCA(x, y)]*2;}
void G_add(int x, int y, int w){G[x].pb(mp(y, w)), G[y].pb(mp(x, w));}
void rebuild(int x){
	vis[x]=tim;int lst=0;
	for(int i=h[x], v; i; i=d[i].nxt)
		if(vis[v=d[i].to]<tim){
			if(!lst) G_add(x, v, d[i].w), lst=x;
			else ++ndc, G_add(lst, ndc, 0), G_add(ndc, v, d[i].w), lst=ndc;
			rebuild(v);
		}
}
void dfs(int x){
	ST[++cnt][0]=x, in[x]=cnt;
	for(auto v:G[x])
		if(!dep[v.st]) 
			dep[v.st]=dep[x]+1, dis[v.st]=dis[x]+v.nd, dfs(v.st), ST[++cnt][0]=x;
}
void findrt(int x, int all){
	vis[x]=tim, siz[x]=1;int sMx=0;
	for(auto v:G[x])
		if(vis[v.st]<tim) 
			findrt(v.st, all), siz[x]+=siz[v.st], sMx=max(sMx, siz[v.st]);
	sMx=max(sMx, all-siz[x]);if(sMn>sMx) sMn=sMx, Rt=x;
}
void add(int x, int y){
	if(tr[x].sn[1]) tr[x].sn[2]=y;
	else if(tr[x].sn[0]) tr[x].sn[1]=y;
	else tr[x].sn[0]=y;
	fa[y]=x;
}
void dfz(int x){
	++tim, findrt(x, siz[x]), vis[x]=INF;
	for(auto v:G[x])
		if(vis[v.st]<INF) 
			++tim, Rt=v.st, sMn=siz[v.st], 
			findrt(v.st, siz[v.st]), add(x, Rt), dfz(Rt);
}
#define id(x) tr[x].id
#define lc(x) tr[x].sn[0]
#define mc(x) tr[x].sn[1]
#define rc(x) tr[x].sn[2]
#define f(x) tr[x].f
#define g(x) tr[x].g
#define h(x) tr[x].h
void renew(int &x, int v, int type, ll el){
	tr[++tot]=tr[x], x=tot;
	h(x)+=type, g(x)+=el, f(x)+=(el=dist(v, id(x))*type);
	if(vis[id(lc(x))]==tim) renew(lc(x), v, type, el);
	if(vis[id(mc(x))]==tim) renew(mc(x), v, type, el);
	if(vis[id(rc(x))]==tim) renew(rc(x), v, type, el);
}
void update(int idx, int type){
	int pos=p[idx];++tim;
	for(int x=pos; x; x=fa[x]) vis[x]=tim;
	rt[idx]=rt[idx-1];
	renew(rt[idx], pos, type, 0);
}
ll res;
int calc(int x, int v){
	int t=0;
	if(vis[id(lc(x))]==tim) t=calc(lc(x), v);
	if(vis[id(mc(x))]==tim) t=calc(mc(x), v);
	if(vis[id(rc(x))]==tim) t=calc(rc(x), v);
	return (res+=f(x)-g(t)+dist(id(x), v)*(h(x)-h(t)), x);
}
ll query(int ver, int pos){
	res=0;++tim;
	for(int x=pos; x; x=fa[x]) vis[x]=tim;
	calc(rt[ver], pos);
	return res;
}
#undef id
#undef lc
#undef mc
#undef rc
#undef f
#undef g
#undef h
signed main(){
	n=read(), m=read();
	for(int i=1; i<=n; ++i) p[i]=read();
	for(int i=1, a, b, c; i<n; ++i)
		a=read(), b=read(), c=read(),
		add(a, b, c), add(b, a, c);
	++tim, ndc=n, rebuild(1);
	dfs(dep[1]=1);
	dep[0]=n+1, lg[0]=-1;
	for(int i=1; i<=cnt; ++i) lg[i]=lg[i>>1]+1;
	for(int i=1; i<=20; ++i)
		for(int x=1; x+(1<<i)-1<=cnt; ++x)
			ST[x][i]=Mx(ST[x][i-1], ST[x+(1<<i-1)][i-1]);
	Rt=1, sMn=ndc, ++tim, findrt(1, ndc), dfz(rt[0]=ROOT=Rt);
	memset(vis, 0, sizeof(vis)), tim=0;
	for(int i=1; i<=ndc; ++i) tr[++tot].id=i;
	for(int i=1; i<=n; ++i) update(i, 1);
	ll ans=0;
	for(int i=1; i<=m; ++i){
		int opt=read();
		if(opt&1){
			int l=(ans%cp)^read(), r=(ans%cp)^read(), x=(ans%cp)^read();
			printf("%lld\n", ans=query(r, x)-query(l-1, x));
		}
		else{
			int x=(ans%cp)^read();
			update(x, -1), swap(p[x], p[x+1]), update(x, 1);
		}
	}
	return 0;
}
 

标签:复健,include,int,tr,CF757G,sn,cp,Day
From: https://www.cnblogs.com/sizeof127/p/17033558.html

相关文章

  • day15
    ##数组![image-20230101170812281](C:\Users\biao\AppData\Roaming\Typora\typora-user-images\image-20230101170812281.png)![image-20230101171524206](C:\Users\bia......
  • 代码随想录day10 LeetCode20 有效的括号 1047. 删除字符串中的所有相邻重复项
     LeetCode20有效的括号 https://leetcode.cn/problems/valid-parentheses/submissions/流程为遍历每一个字符并判断是否为左括号还是有括号,若为左括号则放入栈中,若为......
  • 通关搜索和图论 day_14 -- Dijkstra(朴素版 + 堆优化版)
    最短路分为单源最短路和多源汇最短路单源一般是求从一个点到其他所有点的最短距离源点---起点 汇点---终点多源就是会有很多个询问,起点和终点都是不确定的单源......
  • 算法刷题 Day 10 | 232.用栈实现队列 225. 用队列实现栈
    今日任务:理论基础用栈实现队列用队列实现栈理论基础了解一下栈与队列的内部实现机智,文中是以C++为例讲解的。文章讲解:https://programmercarl.com/%E6%A0%......
  • day2
    DOS命令(diskoperatingsystem)开启Dos控制台的几种方式常见Dos命令开启软件创建目录文件删除目录文件查看IPping打开cmd的方式:Windows:命令指示符......
  • Go语言学习Day1
    1.Go的函数、变量、常量、自定义类型、包(package)的命名方式遵循以下规则:1)首字符可以是任意的Unicode字符或者下划线2)剩余字符可以是Unicode字符、下划线、数字3)字符长......
  • 刷刷刷Day8| 剑指 Offer 05. 替换空格
    剑指Offer05.替换空格LeetCode题目要求请实现一个函数,把字符串s中的每个空格替换成"%20"。示例输入:s="Wearehappy."输出:"We%20are%20happy."解题思路借助......
  • 惊呆了!谷歌Daydream虚拟现实头显售价仅79美元
    据外媒报道,谷歌将于10月4日举办新品发布会。消息人士表示,此次发布会上亮相的除了是两款旗舰智能机,可能还将包括Daydream虚拟现实头显。谷歌已经与多家公司展开合作......
  • day02
    java的三大版本JavaSE标准版(桌面程序,控制台开发)基础核心javaME嵌入式开发(手机,家电)微缩版JAVAEE:企业级开发(web端,服务器开发)JDKJREJVMJDK:javadevelopmentkit用......
  • day1
    学习目标认识软件测试行业软件测试概念:使用技术手段验证软件是否满足需求软件测试目的:用最少的人力,物力,财力,找到软件中的问题并修复,从而降低商业风险测试主流技能功......