[CodeChef-QUERY]Observing the Tree
题目大意:
给你一棵树,一开始每个点的权值都是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的更多相关文章
- Codechef Observing the Tree
Home » Practice(Hard) » Observing the Tree https://www.codechef.com/problems/QUERY Observing the T ...
- BZOJ 3221: [Codechef FEB13] Obserbing the tree树上询问( 可持久化线段树 + 树链剖分 )
树链剖分+可持久化线段树....这个一眼可以看出来, 因为可持久化所以写了标记永久化(否则就是区间修改的线段树的持久化..不会), 结果就写挂了, T得飞起...和管理员拿数据调后才发现= = 做法: ...
- Query on a tree——树链剖分整理
树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...
- SPOJ 375. Query on a tree (树链剖分)
Query on a tree Time Limit: 5000ms Memory Limit: 262144KB This problem will be judged on SPOJ. Ori ...
- QTREE3 spoj 2798. Query on a tree again! 树链剖分+线段树
Query on a tree again! 给出一棵树,树节点的颜色初始时为白色,有两种操作: 0.把节点x的颜色置反(黑变白,白变黑). 1.询问节点1到节点x的路径上第一个黑色节点的编号. 分析 ...
- spoj 375 Query on a tree(树链剖分,线段树)
Query on a tree Time Limit: 851MS Memory Limit: 1572864KB 64bit IO Format: %lld & %llu Sub ...
- 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 ...
- 动态树(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) ...
- 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 ...
- QTREE - Query on a tree
QTREE - Query on a tree 题目链接:http://www.spoj.com/problems/QTREE/ 参考博客:http://blog.sina.com.cn/s/blog ...
随机推荐
- win10安装
1.启动盘制作 首先我们需要登陆“微软中国下载中心”,从中下载一款名为“MediaCreationTool”的工具,利用该工具可以制作Win10安装U盘.直接通过以下地址快速进入“Windows下载中 ...
- Linux压缩打包方法连载之三:bzip2, bzcat 命令
Linux压缩打包方法有多种,本文集中讲解了bzip2, bzcat 命令的使用.案例说明,例如# 与 gzip 同样的,都是在计算压缩比的参数,-9 最佳,-1 最快. AD: 我们遇见Linux压 ...
- Session和Cookie,Django的自动登录机制
什么是Cookie? Cookie是浏览器的本地存储机制,存储服务器返回的各种信息,下次发起请求时再发送给服务端,比如访问baidu 什么是Session? 刚才说道,Cookie存储服务端返回的信息 ...
- java基础27 单例集合Collection及其常用方法
1.集合 集合是存储对象数据的集合容器 1.1.集合比数组的优势 1.集合可以存储任意类型的数据,数组只能存储同一种数据类型的数据 2.集合的长度是变化的,数组的长度是固定的 1.2.数组:存储 ...
- Java事务管理之JDBC
前言 关于Java中JDBC的一些使用可以参见: Java 中使用JDBC连接数据库例程与注意事项 在使用JDBC的使用, 如何进行事务的管理.直接看一下代码 示例代码 /** * @Title: J ...
- Ubuntu 搭建ELK
一.简介 官网地址:https://www.elastic.co/cn/ 官网权威指南:https://www.elastic.co/guide/cn/elasticsearch/guide/curr ...
- 20165333实验一 JAVA开发环境的熟悉
JAVA开发环境的熟悉-1 1建立"自己学号exp1"的目录 2 在"自己学号exp1"目录下建立src,bin等目录 3 javac,java的执行在&quo ...
- java中举例说明对象调用静态成员变量
package org.hanqi.zwxx; public class Test { static int i=47; public void call() { System.out.println ...
- spring boot 之使用mapstruct
最近在阅读swagger源码,当看到 springfox.documentation.swagger2.mappers.ModelMapper 类时,无意中看到该类上面使用的 org.mapstruc ...
- 【LOJ】#2542. 「PKUWC2018」随机游走
题解 虽然我知道minmax容斥,但是--神仙能想到把这个dp转化成一个一次函数啊= = 我们相当于求给定的\(S\)集合里最后一个被访问到的点的时间,对于这样的max的问题,我们可以用容斥把它转化成 ...