日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[HAOI2015]树上操作

發布時間:2024/9/21 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [HAOI2015]树上操作 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目大意:
  給你一棵n個點的樹,以1為根,每個點都有一個點權,要求進行如下操作:
  1.將x這個點的點權加上a;
  2.將以x這個點為根的子樹中每個點的點權加上a;
  3.查詢從x到根的路徑的點權和。

思路:
  樹鏈剖分。
  對于第2種操作,我們不難發現一個子樹中結點在線段樹中的編號一定是連續的。
  于是修改子樹的操作就是線段樹上修改id[x]~id[x]+size[x]-1的操作。

1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 typedef long long int64; 5 inline int getint() { 6 register char ch; 7 register bool neg=false; 8 while(!isdigit(ch=getchar())) if(ch=='-') neg=true; 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return neg?-x:x; 12 } 13 const int N=100001; 14 std::vector<int> e[N]; 15 inline void add_edge(const int &u,const int &v) { 16 e[u].push_back(v); 17 e[v].push_back(u); 18 } 19 int n,size[N],par[N],dep[N],id[N],son[N],top[N],w[N],node[N]; 20 void dfs1(const int &x,const int &par) { 21 ::par[x]=par; 22 dep[x]=dep[par]+1; 23 size[x]=1; 24 for(unsigned i=0;i<e[x].size();i++) { 25 const int &y=e[x][i]; 26 if(y==par) continue; 27 dfs1(y,x); 28 size[x]+=size[y]; 29 if(size[y]>size[son[x]]) son[x]=y; 30 } 31 } 32 void dfs2(const int &x) { 33 id[x]=++id[0]; 34 node[id[x]]=x; 35 if(x==son[par[x]]) { 36 top[x]=top[par[x]]; 37 } else { 38 top[x]=x; 39 } 40 if(son[x]) dfs2(son[x]); 41 for(unsigned i=0;i<e[x].size();i++) { 42 const int &y=e[x][i]; 43 if(y==par[x]||y==son[x]) continue; 44 dfs2(y); 45 } 46 } 47 class SegmentTree { 48 #define _left <<1 49 #define _right <<1|1 50 private: 51 int64 val[N<<2],tag[N<<2]; 52 void push_up(const int &p) { 53 val[p]=val[p _left]+val[p _right]; 54 } 55 int size(const int &b,const int &e) const { 56 return e-b+1; 57 } 58 void push_down(const int &p,const int &b,const int &e) { 59 const int mid=(b+e)>>1; 60 val[p _left]+=tag[p]*size(b,mid); 61 val[p _right]+=tag[p]*size(mid+1,e); 62 tag[p _left]+=tag[p]; 63 tag[p _right]+=tag[p]; 64 tag[p]=0; 65 } 66 public: 67 void build(const int &p,const int &b,const int &e) { 68 if(b==e) { 69 val[p]=w[node[b]]; 70 return; 71 } 72 const int mid=(b+e)>>1; 73 build(p _left,b,mid); 74 build(p _right,mid+1,e); 75 push_up(p); 76 } 77 void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &x) { 78 if(b==l&&e==r) { 79 val[p]+=(int64)x*size(b,e); 80 tag[p]+=x; 81 return; 82 } 83 const int mid=(b+e)>>1; 84 push_down(p,b,e); 85 if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),x); 86 if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,x); 87 push_up(p); 88 } 89 int64 query(const int &p,const int &b,const int &e,const int &l,const int &r) { 90 if(b==l&&e==r) { 91 return val[p]; 92 } 93 const int mid=(b+e)>>1; 94 push_down(p,b,e); 95 int64 ret=0; 96 if(l<=mid) ret+=query(p _left,b,mid,l,std::min(mid,r)); 97 if(r>mid) ret+=query(p _right,mid+1,e,std::max(mid+1,l),r); 98 return ret; 99 } 100 #undef _left 101 #undef _right 102 }; 103 SegmentTree t; 104 inline int64 query(int x) { 105 int64 ret=0; 106 while(x) { 107 ret+=t.query(1,1,n,id[top[x]],id[x]); 108 x=par[top[x]]; 109 } 110 return ret; 111 } 112 int main() { 113 n=getint(); 114 const int m=getint(); 115 for(register int i=1;i<=n;i++) { 116 w[i]=getint(); 117 } 118 for(register int i=1;i<n;i++) { 119 add_edge(getint(),getint()); 120 } 121 dfs1(1,0); 122 dfs2(1); 123 t.build(1,1,n); 124 for(register int i=0;i<m;i++) { 125 const int op=getint(),x=getint(); 126 if(op==1) { 127 t.modify(1,1,n,id[x],id[x],getint()); 128 } 129 if(op==2) { 130 t.modify(1,1,n,id[x],id[x]+size[x]-1,getint()); 131 } 132 if(op==3) { 133 printf("%lld\n",query(x)); 134 } 135 } 136 return 0; 137 } View Code

  題目求的是點到根路徑上的權值和,那么修改單點對整棵子樹所有結點的詢問都有貢獻。
  給整棵子樹增加權值顯然也會對整棵子樹的詢問產生貢獻。
  若v是u的子樹中的一個點,對結點u為根的子樹的每一個結點權值增加a,相當于給針對v的詢問答案增加了(dis(u,v)+1)a。
  考慮將樹“壓扁”,求出樹的DFS序。 對于結點u的子樹,DFS序范圍是dfn[u]~dfn[u]+size[u]-1。
  用線段樹維護兩個值x和y,分別代表需要乘dis的權值和不需要乘dis的權值,詢問時返回dep[u]*x[u]+y[u]即可。

1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 typedef long long int64; 5 inline int getint() { 6 register char ch; 7 register bool neg=false; 8 while(!isdigit(ch=getchar())) if(ch=='-') neg=true; 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return neg?-x:x; 12 } 13 const int N=100001; 14 int w[N],dfn[N],size[N],dep[N]; 15 std::vector<int> e[N]; 16 inline void add_edge(const int &u,const int &v) { 17 e[u].push_back(v); 18 e[v].push_back(u); 19 } 20 void dfs(const int &x,const int &par) { 21 size[x]=1; 22 dfn[x]=++dfn[0]; 23 dep[x]=dep[par]+1; 24 for(unsigned i=0;i<e[x].size();i++) { 25 const int &y=e[x][i]; 26 if(y==par) continue; 27 dfs(y,x); 28 size[x]+=size[y]; 29 } 30 } 31 class SegmentTree { 32 #define _left <<1 33 #define _right <<1|1 34 private: 35 int64 val1[N<<2],val2[N<<2]; 36 public: 37 void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &x,const int64 &y) { 38 if(b==l&&e==r) { 39 val1[p]+=x; 40 val2[p]+=y; 41 return; 42 } 43 const int mid=(b+e)>>1; 44 if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),x,y); 45 if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,x,y); 46 } 47 int64 query(const int &p,const int &b,const int &e,const int &x) { 48 int64 ret=val1[p]*dep[x]+val2[p]; 49 if(b==e) return ret; 50 const int mid=(b+e)>>1; 51 if(dfn[x]<=mid) ret+=query(p _left,b,mid,x); 52 if(dfn[x]>mid) ret+=query(p _right,mid+1,e,x); 53 return ret; 54 } 55 #undef _left 56 #undef _right 57 }; 58 SegmentTree t; 59 int main() { 60 const int n=getint(),m=getint(); 61 for(register int i=1;i<=n;i++) { 62 w[i]=getint(); 63 } 64 for(register int i=1;i<n;i++) { 65 add_edge(getint(),getint()); 66 } 67 dfs(1,0); 68 for(register int i=1;i<=n;i++) { 69 t.modify(1,1,n,dfn[i],dfn[i]+size[i]-1,0,w[i]); 70 } 71 for(register int i=0;i<m;i++) { 72 const int op=getint(); 73 if(op==1) { 74 const int x=getint(),a=getint(); 75 t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,0,a); 76 } 77 if(op==2) { 78 const int x=getint(),a=getint(); 79 t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,a,a-(int64)dep[x]*a); 80 } 81 if(op==3) { 82 const int x=getint(); 83 printf("%lld\n",t.query(1,1,n,x)); 84 } 85 } 86 return 0; 87 } View Code

  同樣還是一種將樹“壓扁”的方法。
  考慮我們之前講過的括號序列。
  操作3中的詢問相當于前綴和。?
  按照括號序列建線段樹,操作1就變成了單點修改,操作2就變成了區間+a/-a。

1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 typedef long long int64; 5 inline int getint() { 6 register char ch; 7 register bool neg=false; 8 while(!isdigit(ch=getchar())) if(ch=='-') neg=true; 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return neg?-x:x; 12 } 13 const int N=100001; 14 int w[N],dfn[N],size[N],dep[N]; 15 std::vector<int> e[N]; 16 inline void add_edge(const int &u,const int &v) { 17 e[u].push_back(v); 18 e[v].push_back(u); 19 } 20 void dfs(const int &x,const int &par) { 21 size[x]=1; 22 dfn[x]=++dfn[0]; 23 dep[x]=dep[par]+1; 24 for(unsigned i=0;i<e[x].size();i++) { 25 const int &y=e[x][i]; 26 if(y==par) continue; 27 dfs(y,x); 28 size[x]+=size[y]; 29 } 30 } 31 class SegmentTree { 32 #define _left <<1 33 #define _right <<1|1 34 private: 35 int64 val1[N<<2],val2[N<<2]; 36 public: 37 void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &x,const int64 &y) { 38 if(b==l&&e==r) { 39 val1[p]+=x; 40 val2[p]+=y; 41 return; 42 } 43 const int mid=(b+e)>>1; 44 if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),x,y); 45 if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,x,y); 46 } 47 int64 query(const int &p,const int &b,const int &e,const int &x) { 48 int64 ret=val1[p]*dep[x]+val2[p]; 49 if(b==e) return ret; 50 const int mid=(b+e)>>1; 51 if(dfn[x]<=mid) ret+=query(p _left,b,mid,x); 52 if(dfn[x]>mid) ret+=query(p _right,mid+1,e,x); 53 return ret; 54 } 55 #undef _left 56 #undef _right 57 }; 58 SegmentTree t; 59 int main() { 60 //freopen("221/haoi2015_t21.in","r+",stdin); 61 const int n=getint(),m=getint(); 62 for(register int i=1;i<=n;i++) { 63 w[i]=getint(); 64 } 65 for(register int i=1;i<n;i++) { 66 add_edge(getint(),getint()); 67 } 68 dfs(1,0); 69 for(register int i=1;i<=n;i++) { 70 t.modify(1,1,n,dfn[i],dfn[i]+size[i]-1,0,w[i]); 71 } 72 for(register int i=0;i<m;i++) { 73 const int op=getint(); 74 if(op==1) { 75 const int x=getint(),a=getint(); 76 t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,0,a); 77 } 78 if(op==2) { 79 const int x=getint(),a=getint(); 80 t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,a,a-(int64)dep[x]*a); 81 } 82 if(op==3) { 83 const int x=getint(); 84 printf("%lld\n",t.query(1,1,n,x)); 85 } 86 } 87 return 0; 88 } View Code

?

轉載于:https://www.cnblogs.com/skylee03/p/8066974.html

總結

以上是生活随笔為你收集整理的[HAOI2015]树上操作的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。