题目大意:
  给你一棵树,一开始每个点的权值都是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. AtCoder ARC 090 E / AtCoder 3883: Avoiding Collision

    题目传送门:ARC090E. 题意简述: 给定一张有 \(N\) 个点 \(M\) 条边的无向图.每条边有相应的边权,边权是正整数. 小 A 要从结点 \(S\) 走到结点 \(T\) ,而小 B 则 ...

  2. unity 欧拉旋转

    欧拉旋转   在文章开头关于欧拉旋转的细节没有解释的太清楚,而又有不少人询问相关问题,我尽量把自己的理解写到这里,如有不对还望指出.     欧拉旋转是怎么运作的     欧拉旋转是我们最容易理解的一 ...

  3. 【web开发】web前端开发常用技术总结归纳

    技术选型规范规范 • Vue版本:2.x • 前端路由:vue-route • 异步请求:Axios • 全局状态管理:VueX • css预处理器:sass/less • h5项目移动端适配规则:使 ...

  4. python网络编程--线程GIL(全局解释器锁)

    一:什么是GIL 在CPython,全局解释器锁,或GIL,是一个互斥体防止多个本地线程执行同时修改同一个代码.这把锁是必要的主要是因为当前的内存管理不是线程安全的.(然而,由于GIL存在,其他特性已 ...

  5. java基础26 线程的通讯;wait()、notify()、notifyAll()等方法

    线程的通讯:一个线程完成了自己的任务时,要通知另一个线程去完成另一个任务 1.1.方法 wait():等待.如果线程执行到了wait()方法,那么该线程会进入等待状态,等待状态下的线程必须要被其他线程 ...

  6. PL/SQL开发中动态SQL的使用方法

    一般的PL/SQL程序设计中,在DML和事务控制的语句中可以直接使用SQL,但是DDL语句及系统控制语句却不能在PL/SQL中直接使用,要想实现在PL/SQL中使用DDL语句及系统控制语句,可以通过使 ...

  7. Struts DynaActionForm example

    The Struts DynaActionForm class is an interesting feature to let you create a form bean dynamically ...

  8. hdu 1760 DFS+博弈

    0代表可放 1带表不能放 每次放一个2*2的方块 不能放者败如果先手必胜则输出Yes 必胜态:从当前状态所能到达的状态中存在一个必败态必败态:从当前状态所能达到的状态全部是必胜态 Sample Inp ...

  9. linux 101 hacks 2date,grep,find

    感觉挨个按着作者来的太蠢了,我还是放自己觉得不错的东西把 用特定格式显示当前时间 以下的方法可以用各种不同的格式来显示当前时间: $ date Thu Jan :: PST $ date --date ...

  10. js 格式化时间,可定义格式

    var format = function (time, format) { var t = new Date(time); var tf = function (i) { return (i < ...