题目链接:

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. CentOS 7+nginx+PHP+php-fpm

    根据网上资料配置: location ~ \.php$ { #include fastcgi_params; fastcgi_pass 127.0.0.1:9000; fastcgi_index in ...

  2. java----牛客练习

    1. 形式参数就是函数定义时设定的参数.例如函数头 int min(int x,int y,int z) 中 x,y,z 就是形参.实际参数是调用函数时所使用的实际的参数.   真正被传递的是实参   ...

  3. BZOJ1283 序列 网络流区间覆盖模型

    就是区间覆盖模型的费用流版. 区间覆盖模型

  4. Python Revisited Day 04 (控制结构与函数)

    目录 4.1 控制结构 4.1.1 条件分支 4.1.2 循环 4.2 异常处理 4.2.1 捕获与产生异常 4.2.2 自定义异常 4.3 自定义函数 Tips 参数默认值为可变时 危险 4.3.1 ...

  5. 软件扒网站? 爬虫? F12查看源码? 查看网页源代码?浏览器sources? 区别和联系!

    1.软件扒网站: 利用各类扒站网站,如仿站小工具8.0,可以按照规则将网站的未经浏览器简析的前端代码扒下来,并整理成css,js,html等文件夹,很方便.(当然看不到ajax等相关代码) 备注:如果 ...

  6. 【转】Docker部署Tomcat及Web应用

    Docker部署Tomcat及Web应用 - Scofield_No1的博客 - CSDN博客https://blog.csdn.net/qq_32351227/article/details/786 ...

  7. NGINX Docs | Load Balancing Apache Tomcat Servers with NGINX Open Source and NGINX Plus

    NGINX Docs | Load Balancing Apache Tomcat Servers with NGINX Open Source and NGINX Plushttps://docs. ...

  8. jvisualvm远程监控 visualgc插件 不受此jvm支持问题

    https://yq.aliyun.com/ziliao/478212 1.修改远程服务器上java设置 vi $JAVA_HOME/jre/lib/security/java.policy    在 ...

  9. Python3练习题 006 冒泡排序

    import random a = [random.randint(1,100) for i in range(10)]def bu(target): length = len(target) whi ...

  10. vue学习的笔记补充

    // vue-router中可以使用 routes:[ { path:'/', name:'index', component:()=>import('./index') } ] // 这种写法 ...