题目链接:

Codeforces757G

题目大意:给出一棵n个点的树及一个1~n的排列pi,边有边权,有q次操作:

1 l r x 求 $\sum\limits_{i=l}^{r}dis(p_{i},x)$

2 x $swap(p_{x},p_{x+1})$

$n,q<=2*10^5$,强制在线

如果多次询问一个点到所有点的距离和,我们可以点分树解决,在点分树上每个点x维护点分树上x子树中的所有点到x的距离和及所有点到x父节点的距离和,每次询问往根爬容斥一下求和即可。如果没有修改操作我们依旧可以每个点对pi建线段树来区间求和,但有了修改操作在修改时时间复杂度会爆炸。我们依据可持久化线段树区间查询的原理也可以对点分树进行可持久化,按照pi的顺序每个版本往点分树中插入一个点的信息,建出对应的一条链并将链上点没建出的子节点连向上一个版本的对应节点,每个点同样维护上述两个信息,但如果直接连接可能一个点会有许多儿子,这样时间复杂度就不对了,因此我们将多叉树转二叉树(具体操作详见边分治讲解),这样一个点的出边最多只有三个,点分树上的子节点数也就最多只有三个。具体的可持久化点分树插入和查询操作参见动态点分治讲解。因为可持久化点分树每个版本相当于保存了一个前缀和,所以查询时直接用r版本的答案减l-1版本的答案即可。对于修改操作,可以发现实际需要修改的就只要x这个版本,那么我们重建x版本的点分树即可。

#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define pr pair<int,ll>
using namespace std;
ll z;
ll ans;
int op;
int cnt;
int tot;
int x,y;
int l,r;
int dfn;
int rot;
int num;
int n,m,q;
ll d[400010];
int a[200010];
int p[400010];
int val[800010];
int to[800010];
int lg[800010];
int mx[400010];
int dep[400010];
int vis[400010];
int size[400010];
int nxt[800010];
int head[400010];
int g[800010][20];
int root[200010];
vector<pr>v[200010];
vector<int>pre[400010];
struct miku
{
int son[3];
int res;
int lty;
ll sum;
ll fsum;
}s[12000010];
void add(int x,int y,ll z)
{
tot++;
nxt[tot]=head[x];
head[x]=tot;
to[tot]=y;
val[tot]=z;
}
void rebuild(int x,int fa)
{
int len=v[x].size();
int last=0;
int tmp=0;
for(int i=0;i<len;i++)
{
int to=v[x][i].first;
int val=v[x][i].second;
if(to==fa)
{
continue;
}
tmp++;
if(tmp==1)
{
add(x,to,val);
add(to,x,val);
last=x;
}
else if(tmp==len-(x!=1))
{
add(last,to,val);
add(to,last,val);
}
else
{
m++;
add(last,m,0);
add(m,last,0);
last=m;
add(m,to,val);
add(to,m,val);
}
}
for(int i=0;i<len;i++)
{
if(v[x][i].first==fa)
{
continue;
}
rebuild(v[x][i].first,x);
}
}
void dfs(int x,int fa)
{
g[++dfn][0]=x;
p[x]=dfn;
for(int i=head[x];i;i=nxt[i])
{
if(to[i]!=fa)
{
d[to[i]]=d[x]+1ll*val[i];
dfs(to[i],x);
g[++dfn][0]=x;
}
}
}
int mn(int x,int y)
{
return d[x]<d[y]?x:y;
}
void ST()
{
for(int i=2;i<=dfn;i++)
{
lg[i]=lg[i>>1]+1;
}
for(int j=1;j<=19;j++)
{
for(int i=1;i+(1<<j)-1<=dfn;i++)
{
g[i][j]=mn(g[i][j-1],g[i+(1<<(j-1))][j-1]);
}
}
}
ll lca(int x,int y)
{
x=p[x],y=p[y];
if(x>y)
{
swap(x,y);
}
int len=lg[y-x+1];
return mn(g[x][len],g[y-(1<<len)+1][len]);
}
ll dis(int x,int y)
{
return d[x]+d[y]-(d[lca(x,y)]<<1);
}
void getroot(int x,int fa)
{
size[x]=1;
mx[x]=0;
for(int i=head[x];i;i=nxt[i])
{
if(to[i]!=fa&&!vis[to[i]])
{
getroot(to[i],x);
size[x]+=size[to[i]];
mx[x]=max(mx[x],size[to[i]]);
}
}
mx[x]=max(mx[x],num-size[x]);
if(mx[x]<mx[rot])
{
rot=x;
}
}
void partation(int x)
{
vis[x]=1;
s[x].lty=x;
for(int i=head[x];i;i=nxt[i])
{
if(!vis[to[i]])
{ num=size[to[i]];
rot=0;
getroot(to[i],0);
dep[rot]=dep[x]+1;
for(int j=0;j<dep[x];j++)
{
pre[rot].push_back(pre[x][j]);
}
for(int j=0;j<=2;j++)
{
if(!s[x].son[j])
{
s[x].son[j]=rot;
pre[rot].push_back(j);
break;
}
}
partation(rot);
}
}
}
void insert(int nex,int &rt,int x,int fa)
{
rt=++cnt;
int now=s[nex].lty;
memcpy(s[rt].son,s[nex].son,sizeof(s[rt].son));
s[rt].lty=now;
s[rt].res=s[nex].res+1;
s[rt].sum=s[nex].sum+dis(now,x);
s[rt].fsum=s[nex].fsum;
if(fa)
{
s[rt].fsum+=dis(s[fa].lty,x);
}
if(s[rt].lty==x)
{
return ;
}
insert(s[nex].son[pre[x][dep[now]]],s[rt].son[pre[x][dep[now]]],x,rt);
}
ll query(int rt,int x)
{
int now;
ll ret=0;
for(int i=0;i<dep[x];i++)
{
now=s[rt].son[pre[x][i]];
ret+=(s[rt].res-s[now].res)*dis(s[rt].lty,x)+(s[rt].sum-s[now].fsum);
rt=now;
}
ret+=s[rt].sum;
return ret;
}
int main()
{
scanf("%d%d",&n,&q);
m=n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<n;i++)
{
scanf("%d%d%lld",&x,&y,&z);
v[x].push_back(make_pair(y,z));
v[y].push_back(make_pair(x,z));
}
rebuild(1,0);
dfs(1,0);
ST();
num=m;
cnt=m;
mx[0]=1<<30;
getroot(1,0);
root[0]=rot;
partation(rot);
for(int i=1;i<=n;i++)
{
insert(root[i-1],root[i],a[i],0);
}
while(q--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d",&l,&r,&x);
l^=ans;
r^=ans;
x^=ans;
ans=query(root[r],x)-query(root[l-1],x);
printf("%lld\n",ans);
ans%=(1<<30);
}
else
{
scanf("%d",&x);
x^=ans;
swap(a[x],a[x+1]);
insert(root[x-1],root[x],a[x],0);
}
}
}

[Codeforces757G]Can Bash Save the Day?——动态点分治(可持久化点分树)的更多相关文章

  1. BZOJ3435[Wc2014]紫荆花之恋——动态点分治(替罪羊式点分树套替罪羊树)

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...

  2. [WC2018]即时战略——动态点分治(替罪羊式点分树)

    题目链接: [WC2018]即时战略 题目大意:给一棵结构未知的树,初始时除1号点其他点都是黑色,1号点是白色,每次你可以询问一条起点为白色终点任意的路径,交互库会自动返回给你这条路径上与起点相邻的节 ...

  3. 【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 ...

  4. P3345 [ZJOI2015]幻想乡战略游戏 动态点分治

    \(\color{#0066ff}{ 题目描述 }\) 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越 ...

  5. 洛谷P3345 [ZJOI2015]幻想乡战略游戏(动态点分治,树的重心,二分查找,Tarjan-LCA,树上差分)

    洛谷题目传送门 动态点分治小白,光是因为思路不清晰就耗费了不知道多少时间去gang这题,所以还是来理理思路吧. 一个树\(T\)里面\(\sum\limits_{v\in T} D_vdist(u,v ...

  6. BZOJ4012 [HNOI2015]开店 (动态点分治)

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  7. BZOJ1095 [ZJOI2007]Hide 捉迷藏 【动态点分治 + 堆】

    题目链接 BZOJ1095 题解 传说中的动态点分治,一直不敢碰 今日一会,感觉其实并不艰涩难懂 考虑没有修改,如果不用树形dp的话,就得点分治 对于每个重心,我们会考虑其分治的子树内所有点到它的距离 ...

  8. 【bzoj1095】[ZJOI2007]Hide 捉迷藏 动态点分治+堆

    题目描述 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这 ...

  9. 动态点分治入门 ZJOI2007 捉迷藏

    传送门 这道题好神奇啊……如果要是不带修改的话那就是普通的点分治了,每次维护子树中距离次大值和最大值去更新. 不过这题要修改,而且还改500000次,总不能每改一次都点分治一次吧. 所以我们来认识一个 ...

随机推荐

  1. springcloud(十三):Eureka 2.X 停止开发,但注册中心还有更多选择:Consul 使用详解

    在上个月我们知道 Eureka 2.X 遇到困难停止开发了,但其实对国内的用户影响甚小,一方面国内大都使用的是 Eureka 1.X 系列,另一方面 Spring Cloud 支持很多服务发现的软件, ...

  2. 一、Xadmin------安装

    翻译:http://xadmin.readthedocs.io/en/docs-chinese 1.安装方法: 1)pip install django-xadmin 2)通过源文件安装,我是通过这种 ...

  3. MySQL之索引原理

    --------------------------------------------------------------------------------堕落的状态,无疑是慢性自杀.想想自己为什 ...

  4. pycharm 常用快捷键操作

    #最重要的快捷键 1. ctrl+shift+A:万能命令行 2. shift两次:查看资源文件 #新建工程第一步操作 1. module设置把空包分层去掉,compact empty middle ...

  5. 两次console.log打印值不同

    var a=[1,2,3] console.log(a); a[2]=10; console.log(a); // 打印结果 // (3) [1, 2, 3] // (3) [1, 2, 10] // ...

  6. Web测试和App测试有什么区别

    WEB测试和App测试从流程上来说,没有区别.都需要经历测试计划方案,用例设计,测试执行,缺陷管理,测试报告等相关活动.从技术上来说,WEB测试和APP测试其测试类型也基本相似,都需要进行功能测试.性 ...

  7. Deflation Methods for Sparse PCA

    目录 背景 总括 Hotelling's deflation 公式 特点 Projection deflation 公式 特点 Schur complement deflation Orthogona ...

  8. Linux安装Apache常见报错(二)

    配置Apache提示报错configure error: APR could not be located. Please use the --with-apr option. 解决办法: ./con ...

  9. [2019BUAA软工助教]答黄杉同学

    [2019BUAA软工助教]答黄杉同学 一.答黄杉同学 011-黄衫博客 我当然不否认软件工程的各种博客是有一定作用的,但是相信大多数人对诸如例会博客并没有什么热情(不过似乎也没有什么其他方法保证团队 ...

  10. 【学习总结】【Java】Git学习-上传本地已有代码到GitHub

    < Git学成归来后的第一次实战 > 上传本地已有代码到GitHub 以之前学了一小半的Java基础教程代码为例 <深坑预警:在GitHub新建仓库那一步,不要勾选readme,不然 ...