[CodeChef-QUERY]Observing the Tree
Posted skylee的OI博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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?
细节:
题目中回退操作以后并不能删掉中间被跳过的操作,比如从第四次操作回退到第三次操作,如果再进行一次修改,那么这个修改操作就是第五次操作。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 #include<cstring> 5 inline int getint() { 6 char ch; 7 while(!isdigit(ch=getchar())); 8 int x=ch^\'0\'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^\'0\'); 10 return x; 11 } 12 const int V=100001,logV=200,M=100001; 13 std::vector<int> e[V]; 14 inline void add_edge(const int u,const int v) { 15 e[u].push_back(v); 16 } 17 int par[V],size[V],son[V],top[V],dep[V],id[V],cnt; 18 void dfs1(const int x,const int p) { 19 dep[x]=dep[p]+1; 20 par[x]=p; 21 size[x]=1; 22 for(unsigned i=0;i<e[x].size();i++) { 23 int &y=e[x][i]; 24 if(y==p) continue; 25 dfs1(y,x); 26 size[x]+=size[y]; 27 if(size[y]>size[son[x]]) son[x]=y; 28 } 29 } 30 void dfs2(const int x) { 31 top[x]=x==son[par[x]]?top[par[x]]:x; 32 id[x]=++cnt; 33 if(son[x]) dfs2(son[x]); 34 for(unsigned i=0;i<e[x].size();i++) { 35 int &y=e[x][i]; 36 if(y==par[x]||y==son[x]) continue; 37 dfs2(y); 38 } 39 } 40 class FotileTree { 41 private: 42 long long first[M*logV],diff[M*logV],sum[M*logV]; 43 int left[M*logV],right[M*logV]; 44 int sz; 45 int newnode() { 46 return ++sz; 47 } 48 void push_up(const int p,const int b,const int e) { 49 sum[p]=sum[left[p]]+sum[right[p]]+(first[p]*2+(e-b)*diff[p])*(e-b+1)/2;\\ 50 } 51 public: 52 int root[M]; 53 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) { 54 if(!p||p==old_p) p=newnode(); 55 first[p]=first[old_p]; 56 diff[p]=diff[old_p]; 57 if((b==l)&&(e==r)) { 58 first[p]+=x; 59 diff[p]+=y; 60 if(!left[p]) left[p]=left[old_p]; 61 if(!right[p]) right[p]=right[old_p]; 62 push_up(p,b,e); 63 return; 64 } 65 int mid=(b+e)>>1; 66 if(l<=mid) modify(left[p],left[old_p],b,mid,l,std::min(mid,r),x,y); 67 if(r>mid) modify(right[p],right[old_p],mid+1,e,std::max(mid+1,l),r,x+(std::max(mid+1,l)-l)*y,y); 68 if(!left[p]) left[p]=left[old_p]; 69 if(!right[p]) right[p]=right[old_p]; 70 push_up(p,b,e); 71 } 72 long long query(const int p,const int b,const int e,const int l,const int r) { 73 if(!p) return 0; 74 if((b==l)&&(e==r)) return sum[p]; 75 int mid=(b+e)>>1; 76 long long ret=(first[p]*2+(l+r-b*2)*diff[p])*(r-l+1)/2; 77 if(l<=mid) ret+=query(left[p],b,mid,l,std::min(mid,r)); 78 if(r>mid) ret+=query(right[p],mid+1,e,std::max(mid+1,l),r); 79 return ret; 80 } 81 }; 82 FotileTree t; 83 inline int get_lca(int x,int y) { 84 while(top[x]!=top[y]) { 85 if(dep[top[x]]<dep[top[y]]) std::swap(x,y); 86 x=par[top[x]]; 87 } 88 if(dep[x]>dep[y]) std::swap(x,y); 89 return x; 90 } 91 int n; 92 inline void modify(const int old_root,int &root,int x,int y,const long long a,long long b) { 93 int lca=get_lca(x,y); 94 int dis=dep[x]+dep[y]-dep[lca]*2; 95 int ax=a,ay=a+b*dis; 96 while(top[x]!=top[y]) { 97 if(dep[top[x]]<dep[top[y]]) { 98 std::swap(x,y); 99 std::swap(ax,ay); 100 b=-b; 101 } 102 t.modify(root,old_root,1,n,id[top[x]],id[x],ax+(dep[x]-dep[top[x]])*b,-b); 103 ax+=(dep[x]-dep[top[x]]+1)*b; 104 x=par[top[x]]; 105 } 106 if(dep[x]<dep[y]) { 107 std::swap(x,y); 108 std::swap(ax,ay); 109 b=-b; 110 } 111 t.modify(root,old_root,1,n,id[y],id[x],ax+(dep[x]-dep[y])*b,-b); 112 } 113 inline long long query(const int root,int x,int y) { 114 long long ret=0; 115 while(top[x]!=top[y]) { 116 if(dep[top[x]]<dep[top[y]]) std::swap(x,y); 117 ret+=t.query(root,1,n,id[top[x]],id[x]); 118 x=par[top[x]]; 119 } 120 if(dep[x]<dep[y]) std::swap(x,y); 121 ret+=t.query(root,1,n,id[y],id[x]); 122 return ret; 123 } 124 inline void rollback(int &cur,const int x) { 125 cur=x; 126 } 127 int main() { 128 n=getint(); 129 int m=getint(); 130 for(int i=1;i<n;i++) { 131 int u=getint(),v=getint(); 132 add_edge(u,v); 133 add_edge(v,u); 134 } 135 dfs1(1,0); 136 dfs2(1); 137 long long lastans=0; 138 int cnt_c=0,cur=0; 139 while(m--) { 140 char op[2]; 141 scanf("%1s",op); 142 switch(op[0]) { 143 case \'c\': { 144 int x=(getint()+lastans)%n+1,y=(getint()+lastans)%n+1,a=getint(),b=getint(); 145 cnt_c++; 146 t.root[cnt_c]=0; 147 modify(t.root[cur],t.root[cnt_c],x,y,a,b); 148 cur=cnt_c; 149 break; 150 } 151 case \'q\': { 152 int x=(getint()+lastans)%n+1,y=(getint()+lastans)%n+1; 153 printf("%lld\\n",lastans=query(t.root[cur],x,y)); 154 break; 155 } 156 case \'l\': { 157 int x=(getint()+lastans)%(cnt_c+1); 158 rollback(cur,x); 159 break; 160 } 161 } 162 } 163 return 0; 164 }
以上是关于[CodeChef-QUERY]Observing the Tree的主要内容,如果未能解决你的问题,请参考以下文章