题面

Description

Nick 是只在动物城以坑蒙拐骗为生的狐狸,儿时受到偏见的伤害,放弃了自己的理想。他被兔子 Judy 设下圈套,被迫与她合作查案,而卷入意想不到的阴谋,历尽艰险后成为搭档。他们识破了绵羊副市长 Bellwether 的计划,发现是 Bellwether 陷害食肉动物,用毒药让食肉动物发狂。Bellwether 被抓到了监狱里面, Nick 和 Judy 过上了一段平静的日子。

然而,故事并没有这样结束,之前在车管所帮他们查车牌号的憨厚的树懒 Flash,才是陷害食肉动物事件的幕后主使。Flash 批量制作了大量让食肉动物发狂的药剂,投放到了食肉动物群中。现在,大量的食肉动物被感染,动物城陷入了一片混乱。警察局的牛局长 Bogo 找到了 Nick,希望他能帮忙。幸运的是,动物城联邦安全局非常有先见之明,他们在每个州都秘密放置了一台机器,机器能生产能量石,这些能量石能让食肉动物恢复正常。现在 Nick 和 Judy 需要去启动这些机器。

动物城是一个有\(N\)个州的联邦,该联邦是一个树的形状,即\(N\)个州共有\(N−1\)条双向道路连接它们,且\(N\)个州是相互连通的。\(N\)个州的编号依次为\(1,2,3,\ldots,N\)。每个州都有且仅有一台机器。一台机器启动后的下一个时刻,就会开始生产能量石, 每个单位时间生产一个。能量石从被生产的时刻开始即生效,每一个单位时间能救一定数量的食肉动物。每个州的解毒机器制造出的能量石的品种可能是不同,第\(i\)个州的机器生产的能量石每个单位时间能救\(a_i\)只食肉动物。

Nick 和 Judy 剩下的时间不多了,他们决定分工合作。 Nick 从\(X\)州出发,目的地为\(Y\) 州,路径为\(X\)到\(Y\)的最短路径。 Nick 从\(X\)州出发的时刻为\(0\),每隔一个单位时间移动一个州。每到一个州, Nick 就会启动这个州的机器。 Nick 想知道他从\(X\)州出发到达\(Y\)州的这段时间里,一共有多少食肉动物被拯救。 Nick 在纠结他的路线选择,因此,他会给你若干的询问,希望比他更聪明的你能帮助他。

在他给你询问的过程中,动物城的局势也在发生着一些变化。动物城联邦安全局可以执行一个修改操作\("X,Y,delta"\),会对\(X\)州到\(Y\)州的最短路径上的州(包括\(X\),\(Y\)州)的机器进行升级,这样,这些机器生产出来的能量石,每个单位时间能救的食肉动物的数量会增加\(delta\)。树懒 Flash 当然也不会坐以待毙,他有一台监控仪,会监控每个州的机器的情况,每当有机器被升级,监控仪就会保存下当前所有州的机器的属性\(a_i\)。 Flash可以用一种神秘的武器执行一个读取操作\("X"\),把当前各个州的机器恢复到第\(X\)次保存的状态($X=0表示未进行过升级时的初始状态)。注意, 只有修改操作执行的时后会进行保存。

现在,依次给出\(M\)个操作,若该操作为一个询问,请你输出 Nick 在当前局面下,他从 \(X\)州出发到达\(Y\)州的这段时间里,一共有多少食肉动物被拯救,由于这个答案可能很大,你只需要输出答案模\(20160501\)后的值。请注意,\(M\)个操作都是被加密过的。

Input

第一行 2 个整数\(N,M\)表示节点个数和操作次数。

接下来\(N−1\)每行\(2\)个整数\(U_i,V_i\)表示了这棵树中\(U_i\)和\(V_i\)这\(2\)个州间有边相连。

接下来一行\(N\)个整数, 表示这\(N\)个州的机器制造的能量的初始值。

接下来\(M\)行每行先有一个数字表示了操作的类型:

类型\(1\),代表一个修改操作,接下来有\(3\)个整数\(X_1,Y_1,delta\),\(X_1,Y_1\)是加密后的数字。正确的\(X=X_1\;xor\;lastans,Y=Y_1\;xor\;lastans\)。\(lastans\)为上次输出的的答案,如果之前没有输出过那么当成\(0\)。

类型 2,代表一个询问操作,接下来有\(2\)个整数\(X_1,Y_1\), 和修改操作一样,正确的 \(X=X_1\;xor\;lastans,Y=Y_1\;xor\;lastans\)。\(lastans\)为上次输出的的答案,如果之前没有输出过那么当成\(0\)。

类型 3,代表一次读取操作,接下来\(1\)个整数\(X1\),正确的\(X=X_1\;xor\;lastans\)。 \(Lastans\)为上次输出的的答案,如果之前没有输出过那么当成\(0\)。

Output

对于每个操作\(2\),输出一行,每行一个数,为所询问的答案模\(20160501\)后的值。

zootopia.in zootopia.out
5 6
1 2
2 3
3 4
4 5
1 2 3 4 5
1 1 5 2
3 0
1 1 3 2
1 3 4 2
3 2
2 1 5
73
5 4
1 2
1 3
2 4
3 5
1 1 1 2 2
1 1 4 2
2 1 4
3 12
2 13 8
12
4

HINT

所有的数据\(1≤a_i,delta≤100000\)。保证数据是合法的,不会读取没保存的局面,即\(X≤\) 已经给出的修改操作次数。

\(N≤100000,M≤100000\);

一开始的初值为 1,2,3,4,5。

第 1 个操作为修改操作,修改后变为 3,4,5,6,7。

第 2 个操作为读取操作,读取第 0 次修改后的局面, a1...a5 变为 1,2,3,4,5。

第 3 个操作为修改操作,修改后变为 3,4,5,4,5。

第 4 个操作为修改操作,修改后变为 3,4,7,6,5。

第 5 个操作为读取操作,读取第 2 次修改后的局面, a1...a5 变为 3,4,5,4,5。

第 6 个操作为询问操作,询问从 1 出发走到 5 的时间内有多少食肉动物被拯救。

Nick 在时刻 4 走到州 5。

此时一共被拯救的动物数量为\((3)+(3×2+4)+(3×3+4×2+5)+(3×4+4×3+5×2+4)=73\)

分析

注意:生产的是能量石,而能量石不会消失,一直会有效果,所以每时刻拯救的动物的数量是递增的,而不是每时刻拯救固定数量!也就是说,询问的不是前缀和,而是双重前缀和!

首先,看到这道题我们就会想到树链剖分。那么我们直接树链剖分。

当统计答案时,我们令\(LCA=lca(X,Y)\),分成\([X,LCA]\)和\([LCA,Y]\)两段分别处理。

  • 当点\(P\in[X,LCA]\)时,由等差数列求和公式,这个点贡献的答案为:$$\begin{align}

    &a_i\times\frac{(dep_i+dep_Y-2dep_{LCA})(dep_i+dep_Y-2dep_{LCA}+1)}{2}\

    =&a_i\times\frac{(dep_Y+dep_Y2-4dep_{LCA}dep_Y+4dep_{LCA}2-2dep_{LCA})+dep_i(1+2dep_Y-4dep_{LCA})+dep_i^2}{2}\

    =&a_i\times\frac{[dep_Y(dep_Y+1)-2dep_{LCA}(2dep_Y-2dep_{LCA}+1)]+dep_i(1+2dep_Y-4dep_{LCA})+dep_i^2}{2}

    \end{align
    }$$

  • 当点\(P\in[LCA,Y]\)时,由等差数列求和公式,这个点贡献的答案为:$$\begin{align}

    &a_i\times\frac{(dep_Y-dep_i)(dep_Y-dep_i+1)}{2}\

    =&a_i\times\frac{(dep_Y+dep_Y2)+dep_i(-1-2dep_Y)+dep_i2}{2}\

    =&a_i\times\frac{dep_Y(dep_Y+1)+dep_i(-1-2dep_Y)+dep_i^2}{2}

    \end{align
    }$$

于是,我们可以维护权值总和权值与深度之积的总和权值与深度的平方之积的总和来统计答案。为了进行更新,我们还要维护深度的总和深度的平方的总和。当询问时,我们把\(a_i\)的系数、\(a_i dep_i\)的系数传进去即可。

这道题还需要访问历史状态,于是我们用可持久化线段树(主席树)进行维护。为了节省空间,采用标记永久化策略。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N=100001;
const ll MOD=20160501;
int n,m,tot,dfx,lst,head[N],v[N<<1],nxt[N<<1],num[N],dep[N],f[N],sum[N],son[N],id[N],dfn[N],pre[N];
void addedge(int x,int y){v[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
void dfs1(int u=1){
sum[u]=1;
for(int i=head[u];~i;i=nxt[i]){
if(v[i]!=f[u]){
f[v[i]]=u;
dep[v[i]]=dep[u]+1;
dfs1(v[i]);
sum[u]+=sum[v[i]];
if(!son[u]||sum[v[i]]>sum[son[u]])son[u]=v[i];
}
}
}
void dfs2(int u=1,int top=1){
id[u]=top;
dfn[u]=++dfx;
pre[dfx]=u;
if(!son[u])return;
dfs2(son[u],top);
for(int i=head[u];~i;i=nxt[i])if(v[i]!=son[u]&&v[i]!=f[u])dfs2(v[i],v[i]);
}
struct PresidentTree{
int nowrt,idx,rtx,rt[N];
struct node{
int ls,rs;
ll sum,dep,dep2,sudep,sudep2,add;
}t[N*50];
void pushup(int o){
t[o].sum=(t[t[o].ls].sum+t[t[o].rs].sum)%MOD;
t[o].dep=(t[t[o].ls].dep+t[t[o].rs].dep)%MOD;
t[o].dep2=(t[t[o].ls].dep2+t[t[o].rs].dep2)%MOD;
t[o].sudep=(t[t[o].ls].sudep+t[t[o].rs].sudep)%MOD;
t[o].sudep2=(t[t[o].ls].sudep2+t[t[o].rs].sudep2)%MOD;
}
void build(int &o,int l,int r){
o=++idx;
if(l==r){
t[o].sum=num[pre[l]];
t[o].dep=dep[pre[l]];
t[o].dep2=dep[pre[l]]*dep[pre[l]]%MOD;
t[o].sudep=t[o].sum*t[o].dep%MOD;
t[o].sudep2=t[o].sum*t[o].dep2%MOD;
return;
}
int mid=(l+r)>>1;
build(t[o].ls,l,mid);
build(t[o].rs,mid+1,r);
pushup(o);
}
pair<ll,ll> update(int rt,int l,int r,int &o,int ql,int qr,ll c){
if(ql>qr)swap(ql,qr);
if(!o){
o=++idx;
t[o]=t[rt];
t[o].ls=t[o].rs=0;
}
if(ql<=l&&r<=qr){
t[o].add=(t[o].add+c)%MOD;
t[o].ls=t[rt].ls;
t[o].rs=t[rt].rs;
return make_pair(t[o].dep,t[o].dep2);
}
int mid=(l+r)>>1;
pair<ll,ll>p,tmp;
if(qr<=mid){
if(!t[o].rs)t[o].rs=t[rt].rs;
if(t[o].ls==t[rt].ls)t[o].ls=0;
p=update(t[rt].ls,l,mid,t[o].ls,ql,qr,c);
}else if(ql>mid){
if(!t[o].ls)t[o].ls=t[rt].ls;
if(t[o].rs==t[rt].rs)t[o].rs=0;
p=update(t[rt].rs,mid+1,r,t[o].rs,ql,qr,c);
}else{
if(t[o].ls==t[rt].ls)t[o].ls=0;
p=update(t[rt].ls,l,mid,t[o].ls,ql,qr,c);
if(t[o].rs==t[rt].rs)t[o].rs=0;
tmp=update(t[rt].rs,mid+1,r,t[o].rs,ql,qr,c);
p.first+=tmp.first;
p.second+=tmp.second;
}
t[o].sum=(t[o].sum+c*(min(qr,r)-max(ql,l)+1))%MOD;
t[o].sudep=(t[o].sudep+c*p.first)%MOD;
t[o].sudep2=(t[o].sudep2+c*p.second)%MOD;
return p;
}
ll query(int o,int l,int r,int ql,int qr,ll tag,ll s1,ll s2){
tag=(tag+t[o].add)%MOD;
if(ql>qr)swap(ql,qr);
if(ql<=l&&r<=qr)return ((t[o].sum+tag*(r-l+1))%MOD*s1+(t[o].sudep+tag*t[o].dep)%MOD*s2+(t[o].sudep2+tag*t[o].dep2)%MOD)%MOD;
ll re=0;
int mid=(l+r)>>1;
if(ql<=mid)re+=query(t[o].ls,l,mid,ql,qr,tag,s1,s2);
if(qr>mid)re+=query(t[o].rs,mid+1,r,ql,qr,tag,s1,s2);
return re%MOD;
}
}pt;
void update(int x,int y,ll del){
++pt.rtx;
while(id[x]!=id[y]){
if(dep[id[x]]<dep[id[y]])swap(x,y);
pt.update(pt.rt[pt.nowrt],1,n,pt.rt[pt.rtx],dfn[id[x]],dfn[x],del);
x=f[id[x]];
}
pt.update(pt.rt[pt.nowrt],1,n,pt.rt[pt.rtx],dfn[x],dfn[y],del);
pt.nowrt=pt.rtx;
}
int LCA(int x,int y){
while(id[x]!=id[y]){
if(dep[id[x]]<dep[id[y]])swap(x,y);
x=f[id[x]];
}
return dep[x]<=dep[y]?x:y;
}
ll query(int x,int y){
ll ans=0;
int b=y,lca=LCA(x,y);
while(id[x]!=id[y]){
if(dep[id[x]]>dep[id[y]]){
ans=(ans+pt.query(pt.rt[pt.nowrt],1,n,dfn[id[x]],dfn[x],0,((ll)dep[b]*(dep[b]+1)-2*dep[lca]*(2*dep[b]-2*dep[lca]+1)+MOD)%MOD,(1+2*dep[b]-4*dep[lca]+MOD)%MOD))%MOD;
x=f[id[x]];
}else{
ans=(ans+pt.query(pt.rt[pt.nowrt],1,n,dfn[id[y]],dfn[y],0,((ll)dep[b]*(dep[b]+1))%MOD,(-1-2*dep[b]+MOD)%MOD))%MOD;
y=f[id[y]];
}
}
if(dep[x]>dep[y])ans=(ans+pt.query(pt.rt[pt.nowrt],1,n,dfn[y],dfn[x],0,((ll)dep[b]*(dep[b]+1)-2*dep[lca]*(2*dep[b]-2*dep[lca]+1)+MOD)%MOD,(1+2*dep[b]-4*dep[lca]+MOD)%MOD))%MOD;
else ans=(ans+pt.query(pt.rt[pt.nowrt],1,n,dfn[x],dfn[y],0,((ll)dep[b]*(dep[b]+1))%MOD,(MOD-1-2*dep[b])%MOD))%MOD;
return ans&1?(ans+MOD)>>1:ans>>1;
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
}
for(int i=1;i<=n;i++)scanf("%d",&num[i]);
dfs1();
dfs2();
pt.build(pt.rt[0],1,n);
for(int i=1;i<=m;i++){
int opt,x,y;
ll del;
scanf("%d",&opt);
if(opt==1){
scanf("%d%d%lld",&x,&y,&del);
update(x^lst,y^lst,del);
}else if(opt==2){
scanf("%d%d",&x,&y);
printf("%d\n",lst=query(x^lst,y^lst));
}else if(opt==3){
scanf("%d",&x);
pt.nowrt=x^lst;
}
}
}

[GDOI2016][树链剖分+主席树]疯狂动物城的更多相关文章

  1. dfs序+主席树 或者 树链剖分+主席树(没写) 或者 线段树套线段树 或者 线段树套splay 或者 线段树套树状数组 bzoj 4448

    4448: [Scoi2015]情报传递 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 588  Solved: 308[Submit][Status ...

  2. Codechef FIBTREE 树链剖分 主席树 LCA 二次剩余 快速幂

    原文链接https://www.cnblogs.com/zhouzhendong/p/CC-FIBTREE.html 题目传送门 - CC-FIBTREE 题意 给定一个有 $n$ 个节点,初始点权都 ...

  3. BZOJ1146 [CTSC2008]网络管理Network 树链剖分 主席树 树状数组

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1146 题意概括 在一棵树上,每一个点一个权值. 有两种操作: 1.单点修改 2.询问两点之间的树链 ...

  4. bzoj 4448 [Scoi2015]情报传递 (树链剖分+主席树)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4448 题面: Description 奈特公司是一个巨大的情报公司,它有着庞大的情报网络 ...

  5. BZOJ 4448: [Scoi2015]情报传递 树链剖分 主席树

    4448: [Scoi2015]情报传递 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4448 Description 奈特公司是一个巨 ...

  6. HDU 5111 Alexandra and Two Trees 树链剖分 + 主席树

    题意: 给出两棵树,每棵树的节点都有一个权值. 同一棵树上的节点的权值互不相同,不同树上节点的权值可以相同. 要求回答如下询问: \(u_1 \, v_1 \, u_2 \, v_2\):询问第一棵树 ...

  7. 5.15 牛客挑战赛40 E 小V和gcd树 树链剖分 主席树 树状数组 根号分治

    LINK:小V和gcd树 时限是8s 所以当时好多nq的暴力都能跑过. 考虑每次询问暴力 跳父亲 这样是nq的 4e8左右 随便过. 不过每次跳到某个点的时候需要得到边权 如果直接暴力gcd的话 nq ...

  8. BZOJ3531 SDOI2014 旅行 - 树链剖分,主席树

    题意:给定一棵树,树上每个点有权值和类型.支持:修改某个点的类型:修改某个点的权值:询问某条链上某个类型的点的和/最大值.点数/类型数/询问数<=100000. 分析: 树链剖分,对每个类型的点 ...

  9. BZOJ4012 HNOI2015开店(树链剖分+主席树)

    考虑这样一个问题:一棵树初始全是白点,有两种操作:把一个点染黑:询问某点到所有黑点的距离之和. 注意到树上两点x和y的距离为depth[x]+depth[y]-depth[lca(x,y)]*2.要求 ...

随机推荐

  1. Entity Framewrok 7beta7中不同版本sql server自动生成分页sql语句的问题

    在EF中,使用linq进行分页是很方便的,假如我们有一个EMP表,结构如下: public class Emp { [Key] public Guid No { get; set; } public ...

  2. arcgis 定位图斑,并且高亮显示

    ///图斑定位 function TabQuery(instance_id, layer_name) { require(["esri/map", "esri/geome ...

  3. Morris.js-利用JavaScript生成时序图

    morris.js是一个轻量级的时间序列javascript类库,是网页显示图表的好工具.github项目地址:点击打开,使用起来很简单,但是需要你有一点网页设计的一些基本知识,对一个网页内容的结构要 ...

  4. 从零开始的全栈工程师——js篇2.11(原型)

    原型 原型分析 1.每个 函数数据类型(普通函数,类)都有一个prototype属性 并且这个属性是一个对象数据类型2.每个Prototype上都有一个constructor属性 并且这个属性值是当前 ...

  5. h5 本地存储

    H5本地存储有两个API,一个是Web Storage,还有一个是Web SQL.不管是哪一个,都是基于JavaScript语言来使用,接下来我就教你怎么使用H5本地存储,本文篇幅较大,JS代码较多, ...

  6. C/C++ sort函数的用法

    sort函数的用法(#include<algorithm>) 做ACM题的时候,排序是一种经常要用到的操作.如果每次都自己写个冒泡之类的O(n^2)排序,不但程序容易超时,而且浪费宝贵的比 ...

  7. python3应用例子01(进度条)

    #!/usr/bin/env python# -*- coding:utf-8 -*- import sysimport time def bar(num, total): rate = num / ...

  8. Linux常用命令-1

    内部命令:属于Shell解释器的一部分(已调入内存) 外部命令:独立于Shell解释器之外的程序文件(在磁盘上) 获得命令帮助 1)内部命令help 查看Bash内部命令的帮助信息 2)命令的“--h ...

  9. SQLSERVER 创建ODBC 报错的解决办法 SQLState:'01000'的解决方案

    错误详情如下: SQLState:'01000' SQL Server 错误:14 [Microsoft][ODBC SQL Server Driver][DBNETLIB] ConnectionOp ...

  10. iptables (1) 原理

    网上看到这个配置讲解得还比较易懂,就转过来了,大家一起看下,希望对您工作能有所帮助. iptables简介 netfilter/iptables(简称为iptables)组成Linux平台下的包过滤防 ...