[BZOJ 3221]Obserbing the tree树上询问

题目

小N最近在做关于树的题。今天她想了这样一道题,给定一棵N个节点的树,节点按1~N编号,一开始每个节点上的权值都是0,接下来有M个操作。第一种操作是修改,给出4个整数X,Y,A,B,对于X到Y路径上加上一个首项是A,公差是B的等差数列,因为小N十分谨慎,所以她每做完一个修改操作就会保存一次,初始状态是第0次保存的局面。第二种操作是求和,给出2个整数X,Y,输出X到Y路径上所有节点的权值和。第三种操作是读取之前第X次保存的局面,所有节点的状态回到之前第X次保存的状态。现在请你对每一个求和操作输出答案。

INPUT

第一行2个整数N,M表示节点个数和操作次数。
接下来N-1行每行2个整数Ui,Vi表示了这棵树中Ui和Vi这2个节点间有边相连。
接下来M行每行先有一个字符表示了操作的类型:
如果是’c’,那么代表了一个修改操作,接下来有4个整数X1,Y1,A,B,为了使得询问在线,正确的X=X1 xor上次输出的数,Y=Y1 xor上次输出的数,如果之前没有输出过那么当成0。
如果是’q’,那么代表了一个求和操作,接下来有2个整数X1,Y1,和修改操作一样需要xor上次输出。
如果是’l’,那么代表了一次读取操作,接下来1个整数X1,正确的X=X1 xor上次输出的数。

OUTPUT

对于每一个求和操作,输出求和后的值。

SAMPLE

INPUT

5 7
1 2
2 3
3 4
4 5
c 2 5 2 3
c 3 4 5 10
q 1 3
l 13
q 13 15
l 6
q 6 4

OUTPUT

12

7

7

解题报告

树剖+可持久化线段树区间修改

唯一的重点在于如何处理等差数列,显然这东西是有顺序的,直接树剖抡链子肯定不行,所以我们找到两点间的$LCA$作为中转站,从$x$更新到$LCA$与从$y$更新到$LCA$分开进行,再记录一下深度差,就可以轻松解决这个鬼畜的问题了

 #include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long L;
inline L read(){
L sum(),f();
char ch(getchar());
for(;ch<''||ch>'';ch=getchar())
if(ch=='-')
f=-;
for(;ch>=''&&ch<='';sum=sum*+(ch^),ch=getchar());
return sum*f;
}
struct edge{
int e;
edge *n;
}a[],*pre[];
int to;
inline void insert(int s,int e){
a[++to].e=e;
a[to].n=pre[s];
pre[s]=&a[to];
}
int n,m,now,tot;
char op[];
int dep[],size[],fa[],son[];
inline void dfs1(int u){
size[u]=;
son[u]=;
dep[u]=dep[fa[u]]+;
for(edge *i=pre[u];i;i=i->n){
int e(i->e);
if(e!=fa[u]){
fa[e]=u;
dfs1(e);
size[u]+=size[e];
if(size[e]>size[son[u]])
son[u]=e;
}
}
}
int timee;
int id[],top[];
inline void dfs2(int u,int rt){
top[u]=rt;
id[u]=++timee;
if(son[u])
dfs2(son[u],rt);
for(edge *i=pre[u];i;i=i->n){
int e(i->e);
if(e!=son[u]&&e!=fa[u])
dfs2(e,e);
}
}
inline int lca(int x,int y){
while(top[x]^top[y]){
if(dep[top[x]]<dep[top[y]])
swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
int rt[],lch[],rch[];
int cnt;
L sum[],add_sx[],add_gc[];
L ans;
inline void update(int &x,int las,int ll,int rr,L sx,L gc,int l,int r){
x=++cnt;
lch[x]=lch[las];
rch[x]=rch[las];
sum[x]=sum[las];
add_sx[x]=add_sx[las];
add_gc[x]=add_gc[las];
if(ll==l&&r==rr){
add_sx[x]+=sx;
add_gc[x]+=gc;
return;
}
sum[x]+=(sx+sx+gc*(L)(rr-ll))*(rr-ll+)/;
int mid((l+r)>>);
if(rr<=mid)
update(lch[x],lch[las],ll,rr,sx,gc,l,mid);
else
if(mid<ll)
update(rch[x],rch[las],ll,rr,sx,gc,mid+,r);
else{
update(lch[x],lch[las],ll,mid,sx,gc,l,mid);
update(rch[x],rch[las],mid+,rr,sx+(mid-ll+)*gc,gc,mid+,r);
}
}
inline L query(int x,int ll,int rr,int l,int r){
L ret((add_sx[x]+(ll-l)*add_gc[x]+add_sx[x]+(rr-l)*add_gc[x])*(rr-ll+)/);
if(ll==l&&r==rr)
return ret+sum[x];
int mid((l+r)>>);
if(rr<=mid)
return ret+query(lch[x],ll,rr,l,mid);
if(mid<ll)
return ret+=query(rch[x],ll,rr,mid+,r);
return ret+query(lch[x],ll,mid,l,mid)+query(rch[x],mid+,rr,mid+,r);
}
inline void change(int x,int y,L sx,L gc){
int f(lca(x,y));
L tp1(),tp2(dep[x]+dep[y]-dep[f]*+);
while(top[x]^top[f]){
tp1+=dep[x]-dep[top[x]]+;
update(rt[now],rt[now],id[top[x]],id[x],sx+(tp1-)*gc,-gc,,n);
x=fa[top[x]];
}
while(top[y]^top[f]){
tp2-=dep[y]-dep[top[y]]+;
update(rt[now],rt[now],id[top[y]],id[y],sx+(tp2-)*gc,gc,,n);
y=fa[top[y]];
}
++tp1;
--tp2;
if(dep[x]<dep[y])
update(rt[now],rt[now],id[x],id[y],sx+(tp1-)*gc,gc,,n);
else
update(rt[now],rt[now],id[y],id[x],sx+(tp2-)*gc,-gc,,n);
}
inline L ask(int x,int y){
L ret();
while(top[x]^top[y]){
if(dep[top[x]]<dep[top[y]])
swap(x,y);
ret+=query(rt[now],id[top[x]],id[x],,n);
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
ret+=query(rt[now],id[x],id[y],,n);
return ret;
}
int main(){
memset(pre,NULL,sizeof(pre));
n=read(),m=read();
for(int i=;i<n;++i){
int x(read()),y(read());
insert(x,y),insert(y,x);
}
dfs1();
dfs2(,);
while(m--){
scanf("%s",op);
if(op[]=='c'){
L x(read()),y(read()),sx(read()),gc(read());
x^=ans,y^=ans;
rt[++tot]=rt[now];
now=tot;
change(x,y,sx,gc);
}
if(op[]=='q'){
L x(read()),y(read());
x^=ans,y^=ans;
ans=ask(x,y);
printf("%lld\n",ans);
}
if(op[]=='l'){
L x(read());
x^=ans;
now=x;
}
}
}

算是真正搞会了可持久化线段树区间修改了,毕竟改了一上午= =

不要问我俩$CE$咋来的,尝试把数组大小多按几个零,或者强行$Replace$ $All$所有的$int$成$L$,把$printf$顺便$Replace$一下,获得$prLf\times 1$,就可以获得$CE\times 2$了QAQ

[BZOJ 3221][Codechef FEB13] Obserbing the tree树上询问的更多相关文章

  1. BZOJ 3221: [Codechef FEB13] Obserbing the tree树上询问( 可持久化线段树 + 树链剖分 )

    树链剖分+可持久化线段树....这个一眼可以看出来, 因为可持久化所以写了标记永久化(否则就是区间修改的线段树的持久化..不会), 结果就写挂了, T得飞起...和管理员拿数据调后才发现= = 做法: ...

  2. bzoj 3221: Obserbing the tree树上询问 树链剖分+线段树

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3221 题解 啊呀...这是昨天的考试题啊...直接就粘了.. 与4515: [Sdoi2 ...

  3. dsu on tree 树上启发式合并 学习笔记

    近几天跟着dreagonm大佬学习了\(dsu\ on\ tree\),来总结一下: \(dsu\ on\ tree\),也就是树上启发式合并,是用来处理一类离线的树上询问问题(比如子树内的颜色种数) ...

  4. Count on a tree 树上主席树

    Count on a tree 树上主席树 给\(n\)个树,每个点有点权,每次询问\(u,v\)路径上第\(k\)小点权,强制在线 求解区间静态第\(k\)小即用主席树. 树上主席树类似于区间上主席 ...

  5. [BZOJ 3509] [CodeChef] COUNTARI (FFT+分块)

    [BZOJ 3509] [CodeChef] COUNTARI (FFT+分块) 题面 给出一个长度为n的数组,问有多少三元组\((i,j,k)\)满足\(i<j<k,a_j-a_i=a_ ...

  6. BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233 ...

  7. BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

    2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/J ...

  8. Codeforces Round #381 (Div. 2) D. Alyona and a tree 树上二分+前缀和思想

    题目链接: http://codeforces.com/contest/740/problem/D D. Alyona and a tree time limit per test2 secondsm ...

  9. Codechef:Path Triples On Tree

    Path Triples On Tree 题意是求树上都不相交或者都相交的路径三元组数量. 发现blog里没什么树形dp题,也没有cc题,所以来丢一道cc上的树形dp题. 比较暴力,比较恶心 #inc ...

随机推荐

  1. 如何在vue项目中引入阿里巴巴的iconfont图库

    1. 打开 http://www.iconfont.cn/ 2. 选择我们喜欢的图标,点击上面的小车,加入图标库,即右侧的购物车 3.点击购物车,点击下载代码 4.解压下载的文件夹,将文件夹复制到 a ...

  2. js和php中几种生成验证码的方式

    之前做过取随机数和生成验证码的练习,都是通过取随机数作为数组下标,然后从数组中取值的方式(js): /*验证码*/ function sj_yzm(){ //存一个包括数字和字母的数组 var zon ...

  3. 湖南集训day5

    难度:☆☆☆☆☆☆☆ /* 二分答案 算斜率算截距巴拉巴拉很好推的公式 貌似没这么麻烦我太弱了...... 唉不重要... */ #include<iostream> #include&l ...

  4. Mobile

    模块===包   传统开发:整个网页我们写了一个js文件,所有的特效都写在里面了. 缺点:耦合度太高,代码关联性太强,不便于后期维护,会造成全局污染. 发生的请求次数过多,依赖模糊,难于维护. 以上都 ...

  5. .Net application,Session,Cache简单比较

    Application 对象用于存储和访问来自任何页面的变量,类似于 session 对象.不同之处在于,所有的用户分享一个 Application 对象,而 session 对象和用户的关系是一一对 ...

  6. 【Leetcode 86】 Partition List

    问题描述: 给定一个list, 将所有小于x的node放到左边,剩下的保持原样. 问题解决: 闲的无聊,用c++和python都做了一遍. 代码如下: # Definition for singly- ...

  7. 为什么选择Sqoop?(三)

    为什么选择 Sqoop? 通常基于三个方面的考虑: 1.它可以高效.可控地利用资源,可以通过调整任务数来控制任务的并发度.另外它还可以配置数据库的访问时间等等. 2.它可以自动的完成数据类型映射与转换 ...

  8. 附加数据库错误代码 - 5120【MSSQL】

    解决方法 数据库所在的文件夹右击打开属性 - 安全 - 给予Authenticated Users用户完全控制权限.然后再附加一次即可成功.

  9. 跨域请求之jsonp

    1.什么是跨域请求: 服务器A上的一个页面,要请求服务器B上的一个处理程序,这就叫做跨域请求 本次的测试页面为: 处理程序kimhandler.ashx,如下: http://qxw119243026 ...

  10. [转]STL之deque容器详解

    Deque 容器 deque容器是C++标准模版库(STL,Standard Template Library)中的部分内容.deque容器类与vector类似,支持随机访问和快速插入删除,它在容器中 ...