[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 ...
随机推荐
- 【多视图几何】TUM 课程 第2章 刚体运动
课程的 YouTube 地址为:https://www.youtube.com/playlist?list=PLTBdjV_4f-EJn6udZ34tht9EVIW7lbeo4 .视频评论区可以找到课 ...
- Hibernate5笔记4--单表查询
单表查询: Hibernate是DAO层技术,对数据的使用,查询是最为重要的.Hibernate的查询技术非常强大,支持原始SQL语句查询,支持QBC查询及Hibernate特有的HQL查询. H ...
- 查看gcc的默认宏定义命令【转】
转自:http://blog.csdn.net/cywosp/article/details/10730931 有些时候我们在编写代码或者阅读开源项目时经常会遇到一些陌生的宏定义,在找遍所有源代码都没 ...
- axios通过django的csrf验证
django会在浏览器的cookie里面保存一项csrftoken=GvzB3ilhlgadishmascacsilreclherlkjhaklsdv3qx4M96XRG88omScDPQaKoMxJ ...
- Vue项目之IE下打开页面是空白
原因是:Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API ,比如 Iterator.Generator.Set.Maps.Proxy.Reflect.Sym ...
- HMM算法
HMM的应用 HMM是生成模型 词性标注:给定一个词的序列(也就是句子),找出最可能的词性序列(标签是词性).如ansj分词和ICTCLAS分词等. 分词:给定一个字的序列,找出最可能的标签序列(断句 ...
- day04作业
1.for(初始化表达式:条件表达式:循环后的操作表达式){ 循环体: } class Test_Sum { public static void main(String[] args) { int ...
- hihocoder1636 Pangu and Stones(区间DP(石子合并变形))
题目链接:http://hihocoder.com/problemset/problem/1636 题目大意:有n堆石头,每次只能合并l~r堆,每次合并的花费是要合并的石子的重量,问你合并n堆石子的最 ...
- Java学习(异常类练习题)
练习题: 1.计算圆的面积,半径不能为零和负数 package com.oracle.Demo01; public class Demo02 { // 写一个计算圆的面积的方法,传一个半径,返回面积 ...
- CRLF LF CR
The Carriage Return (CR) character (0x0D, \r) moves the cursor to the beginning of the line without ...