题目链接:

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. 探究如何永久更改Maven的Dynamic Web Project版本及pom.xml默认配置

    一:问题 在用eclipse创建一个maven project (webApp)时,我们一般会要进行许多麻烦的配置,比如 1.更改Java jdk版本为1.7或1.8(默认1.5) 2.补全src/m ...

  2. 解决在ubuntu上启动的django项目在windows进行访问无法访问的问题

    windows想要访问VMware中Ubuntu Server中Debug模式下的django服务,需要设置django允许非本机ip访问. 设置方法:1.查看虚拟机ip(建议VMware中设置Ubu ...

  3. 微信小程序web-view页面安卓下显示空白的解决办法!!!

    web-view页面在你向地址拼接参数展示页面时,在安卓上有时会显示空白 解决方案: A: 普通不需要参数的话可以直接把地址写在src里,不要去在onLoad里获取你的全局变量后再赋值. B: 如果需 ...

  4. 网络编程-TCP/IP

    TCP/IP五层模型讲解(2分) 我们将应用层,表示层,会话层并作应用层,从tcp/ip五层协议的角度来阐述每层的由来与功能,搞清楚了每层的主要协议 就理解了整个互联网通信的原理. 首先,用户感知到的 ...

  5. 如果需要精确的答案,请避免使用float和double

    Java中的简单浮点数类型float和double不能够进行运算.不光是Java,在其它很多编程语言中也有这样的问题.在大多数情况下,计算的结果是准确的,但是多试几次(可以做一个循环)就可以试出类似上 ...

  6. Elasticsearch--Aggregation详细总结(聚合统计)

    Elasticsearch的Aggregation功能也异常强悍. Aggregation共分为三种:Metric Aggregations.Bucket Aggregations. Pipeline ...

  7. ocrosoft 1015 习题1.22 求一元二次方程a*x^2 + b*x + c = 0的根

    http://acm.ocrosoft.com/problem.php?id=1015 题目描述 求一元二次方程a*x2 + b*x + c = 0的根.系数a.b.c为浮点数,其值在运行时由键盘输入 ...

  8. 封装day.js

    封装day.js import dayjs from 'dayjs' import 'dayjs/locale/zh-cn' import relativeTime from 'dayjs/plugi ...

  9. MySQL — 优化之explain执行计划详解(转)

    EXPLAIN简介 EXPLAIN 命令是查看查询优化器如何决定执行查询的主要方法,使用EXPLAIN,只需要在查询中的SELECT关键字之前增加EXPLAIN这个词即可,MYSQL会在查询上设置一个 ...

  10. [转帖]再次提醒Google Chrome用户应尽快升级浏览器到72.0.3626.121

    再次提醒Google Chrome用户应尽快升级浏览器到72.0.3626.121 转帖地址: https://www.cnbeta.com/articles/tech/825591.htm 国内离线 ...