bzoj4034: [HAOI2015]树上操作
這題其實就是樹剖裸題啊。
然后毒瘤選手由于上題樹剖被卡到哭所以選擇dfs序+樹狀數(shù)組。
不得不說簡單的算法做出來更加難思考。然后網(wǎng)上的dalao們都一筆帶過凈說什么用兩個樹狀數(shù)組維護(hù)就可以啦。
經(jīng)過大半小時的思考,代碼實現(xiàn)還是非常簡單。
這個值得詳細(xì)講講。
?
假如我們弄一個樹狀數(shù)組,然后維護(hù)的是x到根的sum(其實就是詢問的答案嘛),先看第一個操作,單點修改,那么改了這個點,相當(dāng)于把他這一整棵子樹的答案都加上了d,由于用dfs序重新編號,可以發(fā)現(xiàn)子樹中的點都是連續(xù)的,那么樹狀數(shù)組改段求段就可以用差分?jǐn)?shù)組解決。
問題在于第二個操作,修改了整個子樹,對每個節(jié)點y的影響是d*(dep[x]-dep[y]),那么非常難受,因為每個點改變的值和dep有關(guān),并不相同,怎么辦?絕佳的方法就是我們忽略dep的影響,用另一個樹狀數(shù)組維護(hù)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)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jquery的html代码中a的oncl
- 下一篇: 22-高级特性之内建方法(3)