[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的主要内容,如果未能解决你的问题,请参考以下文章

Key-Value Observing (键值监测)

Key-Value Observing (键值监測)

大数据基础zookeeper源代码解析

KVC & KVO

iOS开发-KVO的奥秘

Zookeeper 下 Server 工作状态