1. 程式人生 > >[CodeChef-QUERY]Observing the Tree

[CodeChef-QUERY]Observing the Tree

while b+ getch 後來 端點 dep root 在線 交換

題目大意:
  給你一棵樹,一開始每個點的權值都是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