题目大意:
  给你一棵树,一开始每个点的权值都是0,要求支持一下三种操作:
    1.路径加等差数列。
    2.路径求和。
    3.回到以前的某次操作。
  强制在线。

思路:
  树链剖分+主席树。
  最坏情况下,n个点的树最多会被分成n-1个链,
  这里不能每个点都开一个主席树,因为主席树中要存每个线段树的根结点编号,总共有m次操作,
  因此最坏情况下,总共要存nm个根结点,显然会爆空间,因此我们可以考虑将所有点合并在一个主席树中。
  路径加等差数列时,我们可以先求出两个端点x和y上加的值ax和ay,然后往上爬的过程中根据跳过的长度维护ax和ay即可。
  交换x和y的时候就相当于翻转等差数列,只要交换ax和ay并对公差b取反即可。
  然后随随便便就跑了Rank2(Rank2的vjudge7和Rank3的skylee都是我的程序),0.63s。
  后来想抢Rank发现刷不上去了(似乎CodeChef是根据第一次交的程序来排名的)。
  交的时候发现忘记处理强制在线的操作也能AC?

细节:
  题目中回退操作以后并不能删掉中间被跳过的操作,比如从第四次操作回退到第三次操作,如果再进行一次修改,那么这个修改操作就是第五次操作。

 #include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
inline int getint() {
char ch;
while(!isdigit(ch=getchar()));
int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const int V=,logV=,M=;
std::vector<int> e[V];
inline void add_edge(const int u,const int v) {
e[u].push_back(v);
}
int par[V],size[V],son[V],top[V],dep[V],id[V],cnt;
void dfs1(const int x,const int p) {
dep[x]=dep[p]+;
par[x]=p;
size[x]=;
for(unsigned i=;i<e[x].size();i++) {
int &y=e[x][i];
if(y==p) continue;
dfs1(y,x);
size[x]+=size[y];
if(size[y]>size[son[x]]) son[x]=y;
}
}
void dfs2(const int x) {
top[x]=x==son[par[x]]?top[par[x]]:x;
id[x]=++cnt;
if(son[x]) dfs2(son[x]);
for(unsigned i=;i<e[x].size();i++) {
int &y=e[x][i];
if(y==par[x]||y==son[x]) continue;
dfs2(y);
}
}
class FotileTree {
private:
long long first[M*logV],diff[M*logV],sum[M*logV];
int left[M*logV],right[M*logV];
int sz;
int newnode() {
return ++sz;
}
void push_up(const int p,const int b,const int e) {
sum[p]=sum[left[p]]+sum[right[p]]+(first[p]*+(e-b)*diff[p])*(e-b+)/;\
}
public:
int root[M];
void modify(int &p,const int old_p,const int b,const int e,const int l,const int r,const long long x,const long long y) {
if(!p||p==old_p) p=newnode();
first[p]=first[old_p];
diff[p]=diff[old_p];
if((b==l)&&(e==r)) {
first[p]+=x;
diff[p]+=y;
if(!left[p]) left[p]=left[old_p];
if(!right[p]) right[p]=right[old_p];
push_up(p,b,e);
return;
}
int mid=(b+e)>>;
if(l<=mid) modify(left[p],left[old_p],b,mid,l,std::min(mid,r),x,y);
if(r>mid) modify(right[p],right[old_p],mid+,e,std::max(mid+,l),r,x+(std::max(mid+,l)-l)*y,y);
if(!left[p]) left[p]=left[old_p];
if(!right[p]) right[p]=right[old_p];
push_up(p,b,e);
}
long long query(const int p,const int b,const int e,const int l,const int r) {
if(!p) return ;
if((b==l)&&(e==r)) return sum[p];
int mid=(b+e)>>;
long long ret=(first[p]*+(l+r-b*)*diff[p])*(r-l+)/;
if(l<=mid) ret+=query(left[p],b,mid,l,std::min(mid,r));
if(r>mid) ret+=query(right[p],mid+,e,std::max(mid+,l),r);
return ret;
}
};
FotileTree t;
inline int get_lca(int x,int y) {
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
x=par[top[x]];
}
if(dep[x]>dep[y]) std::swap(x,y);
return x;
}
int n;
inline void modify(const int old_root,int &root,int x,int y,const long long a,long long b) {
int lca=get_lca(x,y);
int dis=dep[x]+dep[y]-dep[lca]*;
int ax=a,ay=a+b*dis;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) {
std::swap(x,y);
std::swap(ax,ay);
b=-b;
}
t.modify(root,old_root,,n,id[top[x]],id[x],ax+(dep[x]-dep[top[x]])*b,-b);
ax+=(dep[x]-dep[top[x]]+)*b;
x=par[top[x]];
}
if(dep[x]<dep[y]) {
std::swap(x,y);
std::swap(ax,ay);
b=-b;
}
t.modify(root,old_root,,n,id[y],id[x],ax+(dep[x]-dep[y])*b,-b);
}
inline long long query(const int root,int x,int y) {
long long ret=;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
ret+=t.query(root,,n,id[top[x]],id[x]);
x=par[top[x]];
}
if(dep[x]<dep[y]) std::swap(x,y);
ret+=t.query(root,,n,id[y],id[x]);
return ret;
}
inline void rollback(int &cur,const int x) {
cur=x;
}
int main() {
n=getint();
int m=getint();
for(int i=;i<n;i++) {
int u=getint(),v=getint();
add_edge(u,v);
add_edge(v,u);
}
dfs1(,);
dfs2();
long long lastans=;
int cnt_c=,cur=;
while(m--) {
char op[];
scanf("%1s",op);
switch(op[]) {
case 'c': {
int x=(getint()+lastans)%n+,y=(getint()+lastans)%n+,a=getint(),b=getint();
cnt_c++;
t.root[cnt_c]=;
modify(t.root[cur],t.root[cnt_c],x,y,a,b);
cur=cnt_c;
break;
}
case 'q': {
int x=(getint()+lastans)%n+,y=(getint()+lastans)%n+;
printf("%lld\n",lastans=query(t.root[cur],x,y));
break;
}
case 'l': {
int x=(getint()+lastans)%(cnt_c+);
rollback(cur,x);
break;
}
}
}
return ;
}

[CodeChef-QUERY]Observing the Tree的更多相关文章

  1. Codechef Observing the Tree

    Home » Practice(Hard) » Observing the Tree   https://www.codechef.com/problems/QUERY Observing the T ...

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

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

  3. Query on a tree——树链剖分整理

    树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...

  4. SPOJ 375. Query on a tree (树链剖分)

    Query on a tree Time Limit: 5000ms Memory Limit: 262144KB   This problem will be judged on SPOJ. Ori ...

  5. QTREE3 spoj 2798. Query on a tree again! 树链剖分+线段树

    Query on a tree again! 给出一棵树,树节点的颜色初始时为白色,有两种操作: 0.把节点x的颜色置反(黑变白,白变黑). 1.询问节点1到节点x的路径上第一个黑色节点的编号. 分析 ...

  6. spoj 375 Query on a tree(树链剖分,线段树)

      Query on a tree Time Limit: 851MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Sub ...

  7. bzoj 3637: Query on a tree VI 树链剖分 && AC600

    3637: Query on a tree VI Time Limit: 8 Sec  Memory Limit: 1024 MBSubmit: 206  Solved: 38[Submit][Sta ...

  8. 动态树(Link Cut Tree) :SPOJ 375 Query on a tree

    QTREE - Query on a tree #number-theory You are given a tree (an acyclic undirected connected graph) ...

  9. hdu 4836 The Query on the Tree(线段树or树状数组)

    The Query on the Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  10. QTREE - Query on a tree

    QTREE - Query on a tree 题目链接:http://www.spoj.com/problems/QTREE/ 参考博客:http://blog.sina.com.cn/s/blog ...

随机推荐

  1. 【codeforces】【比赛题解】#937 CF Round #467 (Div. 2)

    没有参加,但是之后几天打了哦,第三场AK的CF比赛. CF大扫荡计划正在稳步进行. [A]Olympiad 题意: 给\(n\)个人颁奖,要满足: 至少有一个人拿奖. 如果得分为\(x\)的有奖,那么 ...

  2. Jenkins远程调度Shell命令

    http://blog.csdn.net/fireofjava/article/details/40624353 Jenkins服务器为Win7版本,需要远程调用CentOS服务器上Shell脚本,然 ...

  3. ASP.NET MVC 5使用Filter过滤Action参数防止sql注入,让你代码安全简洁

    在开发程序的过程中,稍微不注意就会隐含有sql注入的危险.今天我就来说下,ASP.NET mvc 5使用Filter过滤Action参数防止sql注入,让你代码安全简洁.不用每下地方对参数的值都进行检 ...

  4. FM的推导原理--推荐系统

    FM:解决稀疏数据下的特征组合问题  Factorization Machine(因子分解机) 美团技术团队的文章,觉得写得很好啊:https://tech.meituan.com/deep-unde ...

  5. apache代理配置https

    原文:https://mp.weixin.qq.com/s/Tw4UzX73Q7MSw3GJXnpN8A 微信小程序开发https设置 2017-04-06 格里菲斯 互联网工作者 微信官方规定小程序 ...

  6. thinkphp模版常量替换机制

  7. dedecms自定义模型之独立模型在首页、列表页、内容调用内容

    dedecms关于自定义模型(独立模型)的首页.列表页.内容怎么调用?在后台自定义模型(独立模型)的建立及自定义字段的添加比较简单,需要注意两点: (1)如果某个字段需要在前台列表页显示,则在前台参数 ...

  8. JavaScript 中的回调函数

    原文:http://javascriptissexy.com/ 翻译:http://blog.csdn.net/luoweifu/article/details/41466537 [建议阅读原文,以下 ...

  9. 修饰符(动态String数组篇)--- 常用 解除疑问。

    1.无修饰符----是直接传基本类型的地址过来,并没有把基本类型的指针复制一份入栈,所以一旦修改就是修改原来的值. 2.const 修饰符 与 无修饰符一致. 3.var修饰符 与 上一致. 4.ou ...

  10. 搜索入门之dfs--经典的迷宫问题解析

    今天来谈一下dfs的入门,以前看到的dfs入门,那真的是入门吗,都是把dfs的实现步骤往那一贴,看完是知道dfs的步骤了,但是对于代码实现还是没有概念.今天准备写点自己的心得,真的是字面意思--入门. ...