[Codeforces757G]Can Bash Save the Day?——动态点分治(可持久化点分树)
题目链接:
题目大意:给出一棵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?——动态点分治(可持久化点分树)的更多相关文章
- BZOJ3435[Wc2014]紫荆花之恋——动态点分治(替罪羊式点分树套替罪羊树)
题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...
- [WC2018]即时战略——动态点分治(替罪羊式点分树)
题目链接: [WC2018]即时战略 题目大意:给一棵结构未知的树,初始时除1号点其他点都是黑色,1号点是白色,每次你可以询问一条起点为白色终点任意的路径,交互库会自动返回给你这条路径上与起点相邻的节 ...
- 【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 ...
- P3345 [ZJOI2015]幻想乡战略游戏 动态点分治
\(\color{#0066ff}{ 题目描述 }\) 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越 ...
- 洛谷P3345 [ZJOI2015]幻想乡战略游戏(动态点分治,树的重心,二分查找,Tarjan-LCA,树上差分)
洛谷题目传送门 动态点分治小白,光是因为思路不清晰就耗费了不知道多少时间去gang这题,所以还是来理理思路吧. 一个树\(T\)里面\(\sum\limits_{v\in T} D_vdist(u,v ...
- BZOJ4012 [HNOI2015]开店 (动态点分治)
Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...
- BZOJ1095 [ZJOI2007]Hide 捉迷藏 【动态点分治 + 堆】
题目链接 BZOJ1095 题解 传说中的动态点分治,一直不敢碰 今日一会,感觉其实并不艰涩难懂 考虑没有修改,如果不用树形dp的话,就得点分治 对于每个重心,我们会考虑其分治的子树内所有点到它的距离 ...
- 【bzoj1095】[ZJOI2007]Hide 捉迷藏 动态点分治+堆
题目描述 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这 ...
- 动态点分治入门 ZJOI2007 捉迷藏
传送门 这道题好神奇啊……如果要是不带修改的话那就是普通的点分治了,每次维护子树中距离次大值和最大值去更新. 不过这题要修改,而且还改500000次,总不能每改一次都点分治一次吧. 所以我们来认识一个 ...
随机推荐
- .NET下日志系统的搭建——log4net+kafka+elk
.NET下日志系统的搭建--log4net+kafka+elk 前言 我们公司的程序日志之前都是采用log4net记录文件日志的方式(有关log4net的简单使用可以看我另一篇博客),但是随着 ...
- sublime插件不能使用,提示plugin_host has exited unexpectedly
sublime Text3一打开软件就提示plugin_host has exited unexpectedly,插件不能使用 解决方法很简单: 1.首先,ctrl + shift + p --&g ...
- LeetCode 905. Sort Array By Parity
905. Sort Array By Parity Given an array A of non-negative integers, return an array consisting of a ...
- 03 Django REST Framework 视图和路由
01-DRF中的request 在Django REST Framework中内置的Request类扩展了Django中的Request类,实现了很多方便的功能--如请求数据解析和认证等. 比如,区别 ...
- matplotlib 入门之Usage Guide
文章目录 Usage Guide plotting函数的输入 matplotlib, pyplot, pylab, 三者的联系 Coding style Backends 后端 matplotlib教 ...
- Python—os模块介绍
OS模块 我们平时工作中很常用到的一个模块,通过os模块调用系统命令,获得路径,获取操作系统的类型等都是使用该模块.os 模块提供了很多允许你的程序与操作系统直接交互的功能 得到当前工作目录,即当前P ...
- A+B大数运算
基础加法大数运算: [https://vjudge.net/problem/HDU-1002] 题目: 输入两个长度不超过1000的整数求出sum. 思路: 由于数字很大不能直接加,用字符串形式输入, ...
- 合并dll文件
在使用VS进行.Net编程时,出现了一个奇怪的现象. 在一个类库项目中导入了dll库A后,再导入A的两个依赖项(dll库)B和C,执行“生成”操作时,出现错误信息,提示B和C的库版本与A所需的不一致. ...
- 学习 yii2.0——视图之间相互包含
布局 首先创建一个布局文件simple.php,路径是在views/layout/目录下. <p>this is header</p> <?= $content ?> ...
- SQL not exist out join
sql中exists,not exists的用法 - 飞翔-方向 积累 沉淀 - 博客园http://www.cnblogs.com/mytechblog/articles/2105785.html ...