【CF757G】Can Bash Save the Day?

题意:给你一棵n个点的树和一个排列${p_i}$,边有边权。有q个操作:

1 l r x:询问$\sum\limits_{i=l}^r dist(p_i,x)$
2 x:$swap(a_x,a_{x+1})$

$n,q\le 2\times 10^5$,强制在线。
题解:学到了新姿势:可持久化点分树。我们先将询问变成前缀相减的形式,然后对于每一个前缀都用一个点分树来维护,不难在$O(\log n)$的时间内处理掉一组询问。现在问题在于如何构建可持久化点分树。

首先,点分树的深度是$O(\log n)$的,所以我们在加入一个新点的时候可以新建这个点到根的那条链。而对于2操作,我们只需要重新构建第x棵点分树就好了。但是有一个问题,我们再新建一个点的时候需要复制这个点所有儿子的信息,但是一个点的儿子数量是$O(n)$级别的,怎么办?

这就需要我们对原树进行预处理,将多叉树转变为二叉树。具体方法:假如点x的儿子分别为$c_1,c_2,...c_k$,则我们新建k-2个点$t_1,t_2...t_{k-2}$,连边:$x-t_1,t_1-t_2,...,t_{k-3}-t_{k-2}$,$c_1-x,c_2-t_1,c_3-t_2,...c_{k-1}-t_{k-2},c_k-t_{k-2}$即可。总新建的点数显然不超过n。

那么我们在点分树上的每个点最多就只有3个儿子了。再记录一下从根走到每个点的路径就很容易处理了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=200010;
typedef long long ll;
int n,m,N,cnt,Cnt,msk,mn,tot,root;
ll ans;
int to[maxn<<2],nxt[maxn<<2],head[maxn<<1],val[maxn<<2],To[maxn<<1],Nxt[maxn<<1],Head[maxn],Val[maxn<<1];
int p[maxn],siz[maxn<<1],Log[maxn<<2],d[maxn],vis[maxn<<1],dep[maxn<<1],pos[maxn<<1],rt[maxn];
ll md[20][maxn<<2],des[maxn<<1];
vector<int> step[maxn<<1];
struct node
{
int ch[3],cnt,org; ll s1,s2;
}s[maxn*60];
inline void add(int a,int b,int c)
{
to[cnt]=b,val[cnt]=c,nxt[cnt]=head[a],head[a]=cnt++;
}
inline void Add(int a,int b,int c)
{
To[Cnt]=b,Val[Cnt]=c,Nxt[Cnt]=Head[a],Head[a]=Cnt++;
}
void dfs1(int x,int fa)
{
for(int i=Head[x],last=0,tmp=0;i!=-1;i=Nxt[i]) if(To[i]!=fa)
{
tmp++;
if(tmp==1) add(x,To[i],Val[i]),add(To[i],x,Val[i]),last=x;
else if(tmp==d[x]-(x!=1)) add(last,To[i],Val[i]),add(To[i],last,Val[i]);
else
{
N++,add(last,N,0),add(N,last,0),last=N;
add(N,To[i],Val[i]),add(To[i],N,Val[i]);
}
}
for(int i=Head[x];i!=-1;i=Nxt[i]) if(To[i]!=fa) dfs1(To[i],x);
}
void dfs2(int x,int fa)
{
md[0][++pos[0]]=des[x],pos[x]=pos[0];
for(int i=head[x];i!=-1;i=nxt[i]) if(to[i]!=fa) des[to[i]]=des[x]+val[i],dfs2(to[i],x),md[0][++pos[0]]=des[x];
}
void getrt(int x,int fa)
{
siz[x]=1;
int tmp=0,i;
for(i=head[x];i!=-1;i=nxt[i]) if(!vis[to[i]]&&to[i]!=fa)
{
getrt(to[i],x),siz[x]+=siz[to[i]],tmp=max(tmp,siz[to[i]]);
}
tmp=max(tmp,tot-siz[x]);
if(tmp<mn) mn=tmp,root=x;
}
void solve(int x)
{
vis[x]=1,s[x].org=x;
for(int i=head[x];i!=-1;i=nxt[i]) if(!vis[to[i]])
{
tot=siz[to[i]],mn=1<<30,getrt(to[i],x),dep[root]=dep[x]+1;
for(int j=0;j<dep[x];j++) step[root].push_back(step[x][j]);
if(!s[x].ch[0]) s[x].ch[0]=root,step[root].push_back(0);
else if(!s[x].ch[1]) s[x].ch[1]=root,step[root].push_back(1);
else s[x].ch[2]=root,step[root].push_back(2);
solve(root);
}
}
inline ll lca(int a,int b)
{
a=pos[a],b=pos[b];
if(a>b) swap(a,b);
int k=Log[b-a+1];
return min(md[k][a],md[k][b-(1<<k)+1]);
}
inline ll dis(int a,int b)
{
return des[a]+des[b]-2*lca(a,b);
}
void insert(int x,int &y,int a,int b,int fa)
{
y=++tot;
int z=s[x].org;
memcpy(s[y].ch,s[x].ch,sizeof(s[y].ch)),s[y].org=z;
s[y].cnt=s[x].cnt+b,s[y].s1=s[x].s1+b*dis(z,a),s[y].s2=s[x].s2;
if(fa) s[y].s2+=b*dis(s[fa].org,a);
if(s[y].org==a) return ;
insert(s[x].ch[step[a][dep[z]]],s[y].ch[step[a][dep[z]]],a,b,y);
}
ll find(int x,int y)
{
int i,u;
ll ret=0;
for(i=0;i<dep[y];i++)
{
u=s[x].ch[step[y][i]];
ret+=(s[x].cnt-s[u].cnt)*dis(s[x].org,y)+(s[x].s1-s[u].s2);
x=u;
}
return ret+s[x].s1;
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
int main()
{
//freopen("cf757G.in","r",stdin);
N=n=rd(),m=rd(),msk=(1<<30)-1;
int i,j,a,b,c;
for(i=1;i<=n;i++) p[i]=rd();
memset(head,-1,sizeof(head)),memset(Head,-1,sizeof(Head));
for(i=1;i<n;i++) a=rd(),b=rd(),c=rd(),Add(a,b,c),Add(b,a,c),d[a]++,d[b]++;
dfs1(1,0),dfs2(1,0);
for(i=2;i<=pos[0];i++) Log[i]=Log[i>>1]+1;
for(j=1;(1<<j)<=pos[0];j++) for(i=1;i+(1<<j)-1<=pos[0];i++) md[j][i]=min(md[j-1][i],md[j-1][i+(1<<(j-1))]);
tot=N,mn=1<<30,getrt(1,0),rt[0]=root,solve(root);
tot=N;
for(i=1;i<=n;i++)
insert(rt[i-1],rt[i],p[i],1,0);
for(i=1;i<=m;i++)
{
if(rd()==1)
{
a=rd()^ans,b=rd()^ans,c=rd()^ans;
ans=find(rt[b],c)-find(rt[a-1],c);
printf("%lld\n",ans);
ans&=msk;
}
else
{
a=rd()^ans;
insert(rt[a-1],rt[a],p[a],0,0),swap(p[a],p[a+1]),insert(rt[a],rt[a],p[a],1,0);
}
}
return 0;
}//5 5 4 5 1 3 2 4 2 4 1 3 9 4 1 4 4 5 2 1 1 5 4 1 22 20 20 2 38 2 39 1 36 38 38

【CF757G】Can Bash Save the 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 ...

  2. [Codeforces757G]Can Bash Save the Day?——动态点分治(可持久化点分树)

    题目链接: Codeforces757G 题目大意:给出一棵n个点的树及一个1~n的排列pi,边有边权,有q次操作: 1 l r x 求 $\sum\limits_{i=l}^{r}dis(p_{i} ...

  3. 51nod 1295 XOR key 可持久化01字典树

    题意 给出一个长度为\(n\)的正整数数组\(a\),再给出\(q\)个询问,每次询问给出3个数,\(L,R,X(L<=R)\).求\(a[L]\)至\(a[R]\)这\(R-L+1\)个数中, ...

  4. HDU 6191 2017ACM/ICPC广西邀请赛 J Query on A Tree 可持久化01字典树+dfs序

    题意 给一颗\(n\)个节点的带点权的树,以\(1\)为根节点,\(q\)次询问,每次询问给出2个数\(u\),\(x\),求\(u\)的子树中的点上的值与\(x\)异或的值最大为多少 分析 先dfs ...

  5. FHQ Treap及其可持久化与朝鲜树式重构

    FHQ Treap,又称无旋treap,一种不基于旋转机制的平衡树,可支持所有有旋treap.splay等能支持的操作(只有在LCT中会比splay复杂度多一个log).最重要的是,它是OI中唯一一种 ...

  6. 洛谷P3919 【模板】可持久化数组 [主席树]

    题目传送门 可持久化数组 题目描述 如题,你需要维护这样的一个长度为 $N$ 的数组,支持如下几种操作 在某个历史版本上修改某一个位置上的值 访问某个历史版本上的某一位置的值 此外,每进行一次操作(对 ...

  7. P5283 [十二省联考2019]异或粽子 可持久化01Trie+线段树

    $ \color{#0066ff}{ 题目描述 }$ 小粽是一个喜欢吃粽子的好孩子.今天她在家里自己做起了粽子. 小粽面前有 \(n\) 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 ...

  8. luogu 2483 K短路 (可持久化左偏树)

    题面: 题目大意:给你一张有向图,求1到n的第k短路 $K$短路模板题 假设整个图的边集为$G$ 首先建出以点$n$为根的,沿反向边跑的最短路树,设这些边构成了边集$T$ 那么每个点沿着树边走到点$n ...

  9. luogu P6088 [JSOI2015]字符串树 可持久化trie 线段树合并 树链剖分 trie树

    LINK:字符串树 先说比较简单的正解.由于我没有从最简单的考虑答案的角度思考 所以... 下次还需要把所有角度都考察到. 求x~y的答案 考虑 求x~根+y~根-2*lca~根的答案. 那么问题变成 ...

随机推荐

  1. VIM复制粘贴大全[转]

    用vim这么久 了,始终也不知道怎么在vim中使用系统粘贴板,通常要在网上复制一段代码都是先gedit打开文件,中键粘贴后关闭,然后再用vim打开编辑,真的不 爽:上次论坛上有人问到了怎么在vim中使 ...

  2. 【git】git pull

    http://www.01happy.com/git-resolve-conflicts/

  3. 最新Java面试题及答案整理

    基础篇 一.基本功 面向对象特征 封装,继承,多态和抽象 1. 封装 封装给对象提供了隐藏内部特性和行为的能力.对象提供一些能被其他对象访问的方法来改变它内部的数据.在 Java 当中,有 3 种修饰 ...

  4. crontab修改默认编辑器

    crontab默认编辑器为nano 修改crontab默认编辑器为vi或者其他的编辑器 可以用命令select-editor修改 改为3或者4 再用crontab -e 就是vim打开了

  5. ambari HDFS-HA 回滚

    curl -u admin:admin -H "X-Requested-By: ambari" -X GET http://zwshen86:8080/api/v1/cluster ...

  6. docker dockerfile构建自己的tomcat镜像

    文件 1.apache-tomcat-8.5.24.tar.gz, jdk-8u151-linux-x64.tar.gz Dockerfile文件: FROM centosWORKDIR /usrCO ...

  7. iOS AppsFlyer的使用注意事项

    AppFlyer 是近期比較火的一款广告追踪统计工具,当然统计的功能友盟也能够实现,而appsflyer更是具有定向投放,是app跳转到对应的页面. 详细的:当点击广告的时候,假设没有安装应用.则会跳 ...

  8. python使用代理访问服务器

    python使用代理访问服务器主要有一下3个步骤: 1.创建一个代理处理器ProxyHandler: proxy_support = urllib.request.ProxyHandler(),Pro ...

  9. Web暴力破解--前端JS表单加密进行爆破

    0x01 前言 常见的js实现加密的方式有:md5.base64.shal,写了一个简单的demo作为测试. 0x02 代码 login.html <!DOCTYPE HTML> < ...

  10. 【RF库Collections测试】Reverse List

    Name:Reverse ListSource:Collections <test library>Arguments:[ list_ ]Reverses the given list i ...