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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

bzoj4034: [HAOI2015]树上操作

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

這題其實就是樹剖裸題啊。

然后毒瘤選手由于上題樹剖被卡到哭所以選擇dfs序+樹狀數(shù)組。

不得不說簡單的算法做出來更加難思考。然后網(wǎng)上的dalao們都一筆帶過凈說什么用兩個樹狀數(shù)組維護就可以啦。

經(jīng)過大半小時的思考,代碼實現(xiàn)還是非常簡單。

這個值得詳細講講。

?

假如我們弄一個樹狀數(shù)組,然后維護的是x到根的sum(其實就是詢問的答案嘛),先看第一個操作,單點修改,那么改了這個點,相當于把他這一整棵子樹的答案都加上了d,由于用dfs序重新編號,可以發(fā)現(xiàn)子樹中的點都是連續(xù)的,那么樹狀數(shù)組改段求段就可以用差分數(shù)組解決。

問題在于第二個操作,修改了整個子樹,對每個節(jié)點y的影響是d*(dep[x]-dep[y]),那么非常難受,因為每個點改變的值和dep有關(guān),并不相同,怎么辦?絕佳的方法就是我們忽略dep的影響,用另一個樹狀數(shù)組維護d,那么問題又來了,x肯定不是時時相同的,雖然詢問y的時候可以知道dep[y],但是dep[x]仍然不確定,為了可以確定,那么對于每次這種修改,我們就在第一個樹狀數(shù)組給它減去d*(dep[x]-1),這樣一來,就把這個操作轉(zhuǎn)化成增加x整個子樹和x到根的路徑上的點,那么對于每個點,增加的數(shù)就變成d*dep[y],那么求解的時候,就可以心安理得的用第一個樹狀數(shù)組的值+第二個樹狀數(shù)組的值*d了。

#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL;int n,m;struct node {int x,y,next; }a[210000];int len,last[110000]; void ins(int x,int y) {len++;a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len; }int z,dep[110000],l[110000],r[110000]; void dfs(int x,int f) {l[x]=++z;for(int k=last[x];k;k=a[k].next){int y=a[k].y;if(y!=f)dep[y]=dep[x]+1, dfs(y,x);}r[x]=z; }//---------init----------------- LL s[2][110000]; int lowbit(int x){return x&-x;} void change(int w,int x,LL k) {while(x<=n){s[w][x]+=k;x+=lowbit(x);} } LL getsum(int w,int x) {LL ret=0;while(x>=1){ret+=s[w][x];x-=lowbit(x);}return ret; }//-----------bit-------------- LL point[110000]; int main() {scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%lld",&point[i]);len=0;memset(last,0,sizeof(last));int x,y;for(int i=1;i<n;i++){scanf("%d%d",&x,&y);ins(x,y);ins(y,x);}z=0;dep[1]=1;dfs(1,0);//initfor(int i=1;i<=n;i++)change(0,l[i],point[i]), change(0,r[i]+1,-point[i]);int op;LL d;for(int i=1;i<=m;i++){scanf("%d",&op);if(op==1){scanf("%d%lld",&x,&d);change(0,l[x],d);change(0,r[x]+1,-d);}else if(op==2){scanf("%d%lld",&x,&d);change(0,l[x],-d*(dep[x]-1));change(0,r[x]+1,d*(dep[x]-1));change(1,l[x],d);change(1,r[x]+1,-d);}else{scanf("%d",&x);printf("%lld\n", getsum(0,l[x]) + dep[x]*getsum(1,l[x]) );}}return 0; }

?

轉(zhuǎn)載于:https://www.cnblogs.com/AKCqhzdy/p/8490480.html

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。