CF757G Can Bash Save the Day? (复健 Day 1)
先差分为 \(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;
}
CF757G Can Bash Save the Day? (复健 Day 1)的更多相关文章
- CF757G Can Bash Save the Day?
CF757G Can Bash Save the Day? #include<bits/stdc++.h> #define RG register #define IL inline #d ...
- 【CF757G】Can Bash Save the Day? 可持久化点分树
[CF757G]Can Bash Save the Day? 题意:给你一棵n个点的树和一个排列${p_i}$,边有边权.有q个操作: 1 l r x:询问$\sum\limits_{i=l}^r d ...
- 2019NOIP算法复健+学习
前言: 原本因为kma太弱,很多算法没学学了也不会用,打算设置密码给自己看.后来想了想,觉得也没有必要,既然决定了要学些东西到脑子里,就没什么好丢人的. 注:"×"意为完全没学,& ...
- 复健小CM
系统 : Windows xp 程序 : Keygenme # 2 程序下载地址 :http://pan.baidu.com/s/1qYIk2HQ 要求 : 注册机编写 使用工具 : OD 可在“PE ...
- [Codeforces757G]Can Bash Save the Day?——动态点分治(可持久化点分树)
题目链接: Codeforces757G 题目大意:给出一棵n个点的树及一个1~n的排列pi,边有边权,有q次操作: 1 l r x 求 $\sum\limits_{i=l}^{r}dis(p_{i} ...
- 并不对劲的复健训练-CF1187D
题目大意 有两个长度为\(n\)的序列\(a_1,...,a_n\),\(b_1,...,b_n\)(\(a,b\leq n\leq 3\times 10^5\) ).一次操作是选取 \([l,r]\ ...
- 并不对劲的复健训练-bzoj5250:loj2473:p4365:[九省联考2018]秘密袭击
题目大意 有一棵\(n\)(\(n\leq 1666\))个点的树,有点权\(d_i\),点权最大值为\(w\)(\(w\leq 1666\)).给出\(k\)(\(k\leq n\)),定义一个选择 ...
- 并不对劲的复健训练-bzoj5339:loj2578:p4593:[TJOI2018]教科书般的亵渎
题目大意 题目链接 题解 先将\(a\)排序. \(k\)看上去等于怪的血量连续段的个数,但是要注意当存在\(a_i+1=a_{i+1}\)时,虽然它们之间的连续段为空,但是还要算上:而当\(a_m= ...
- 并不对劲的复健训练-CF1205B Shortest Cycle
题目大意 有\(n\)(\(n\leq 10^5\))个数\(a_1,...,a_n\)(\(a\leq 10^{18}\)).有一个图用这个方法生成:若\(a_i\)按位与\(a_j\)不为0,则在 ...
- 并不对劲的复健训练-p5212 SubString
题目大意 有一个串\(s\),一开始只知道它的一个前缀.有\(q\)(\(q\leq 10^4\))个操作,操作有两种:1.给一个字符串,表示\(s\)(\(s\)总长\(\leq 6\times 1 ...
随机推荐
- Redis 应用场景之短信验证码
应用场景 以 OSChina 账号注册 为例...讲错了请留言批评指正... 逻辑场景 用户操作: 用户输入手机号, 然后点击获取验证码. 前端逻辑: ajax 发起请求, 参数带上手机号. 后端逻辑 ...
- Win10怀旧--win7体验
右键菜单变窄(1903以后失效) HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\FlightedFeatures Immer ...
- chatops
ChatOps是什么? ChatOps, 简单地说,这是一种方法,允许团队以聊天室的方式来协作和管理其基础结构.代码和数据的许多方面.通过使用聊天机器人和脚本,团队可以执行命令.查询信息,并将知识分发 ...
- 又一款眼前一亮的Linux终端工具!
大家好,我是良许. 最近二舅视频刷爆了全网,大家有没去看呢?强烈推荐大家观看一波,也就 11 分钟,保证会触动你的泪点. 不过今天不讲二舅哈,还是来聊聊技术. 今天给大家介绍一款最近发现的功能十分强大 ...
- 🎀OpenTelemetry探针介绍及使用
简介 OpenTelemetry(简称 Otel)是由 CNCF 主导的云原生可观测性标准框架,用于统一采集.处理和导出分布式系统中的遥测数据(如追踪.指标.日志).其核心目标是通过标准化协议和工具集 ...
- IDEA插件-Translation
简介 Translation是一个为IntelliJ IDEA和其他基于JetBrains的IDE(如 PyCharm.WebStorm 等)设计的插件.这个插件的主要功能是帮助开发者在编写代码或文档 ...
- 康谋分享 | aiSim5激光雷达LiDAR模型验证方法(二)
aiSim中的LiDAR是一种基于光线追踪的传感器,能够模拟真实LiDAR发射的激光束,将会生成LAS v1.4标准格式的3D点云,包含了方位角.俯仰角和距离等. aiSim能够模拟LiDAR单态(M ...
- 大模型参数组成计算QwQ-32B为例
计算大模型参数量主要依赖于模型的架构和各层配置,我们把常用大模型分为三层:输入层.transformer层.输出层. 输入层 参数组成是Embedding的词表总和 transformer层 参数组成 ...
- AutoFac(三)——装配扫描(批量注册之扫描模块)
RegisterAssemblyModules() 模块扫描使用RegisterAssemblyModules()注册方法执行,该方法完全按照其名称执行.它扫描提供的Autofac模块的程序集,创建模 ...
- 打造企业级AI文案助手:GPT-J+Flask全栈开发实战
一.智能文案革命的序幕:为什么需要AI文案助手? 在数字化营销时代,内容生产效率成为企业核心竞争力.据统计,营销人员平均每天需要撰写3.2篇文案,而传统人工创作存在三大痛点: 效率瓶颈:创意构思到成文 ...