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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Change FZU - 2277(线段树+dfs序)

發布時間:2023/12/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Change FZU - 2277(线段树+dfs序) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

There is a rooted tree with n nodes, number from 1-n. Root’s number is 1.Each node has a value ai.

Initially all the node’s value is 0.

We have q operations. There are two kinds of operations.

1 v x k : a[v]+=x , a[v’]+=x-k (v’ is child of v) , a[v’’]+=x-2*k (v’’ is child of v’) and so on.

2 v : Output a[v] mod 1000000007(10^9 + 7).

Input
First line contains an integer T (1 ≤ T ≤ 3), represents there are T test cases.

In each test case:

The first line contains a number n.

The second line contains n-1 number, p2,p3,…,pn . pi is the father of i.

The third line contains a number q.

Next q lines, each line contains an operation. (“1 v x k” or “2 v”)

1?≤?n?≤?3*10^5

1?≤?pi?<?i

1?≤?q?≤?3*10^5

1?≤?v?≤?n; 0?≤?x?<?10^9?+?7; 0?≤?k?<?10^9?+?7

Output
For each operation 2, outputs the answer.

Sample Input
1
3
1 1
3
1 1 2 1
2 1
2 2
Sample Output
2
1
這個題目的出奇之處就是在更新的時候,每個點的更新多少是不一樣的。

我們看題干這里,每個節點更新的是隨著深度的增加逐漸遞減的,我們必須找出這之間的規律才能做。假如樹的祖先深度是deep[v],那么它的一個子節點u的深度是deep[u],子節點更新的值是
x-(deep[u]-deep[v])*k。對于v所有的子樹來說,都會更新的值是x+deep[v]*k。剩下的就和自己的深度有關了。那么我們線段樹維護兩個lazy,一個記錄都增加的值,另一個就記錄k。
代碼如下:

#include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<cstring> #define ll unsigned long long #define mod 1000000007 using namespace std;const int maxx=3e5+100; struct node{int l;int r;ll lazy1;ll lazy2;ll sum; }p[maxx<<2]; struct edge{int to;int next; }e[maxx]; int deep[maxx],in[maxx],out[maxx],pre[maxx],head[maxx<<1]; int tot,sign,n,m; /*----------------事前準備---------------*/ inline void init() {memset(head,-1,sizeof(head));tot=sign=0; } inline void read(int &x)//快速讀入 {int f=1;x=0;char s=getchar();while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}x*=f; } void read1(ll &x) {int f=1;x=0;char s=getchar();while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}x*=f; } inline void add(int u,int v) {e[tot].to=v,e[tot].next=head[u],head[u]=tot++; } /*--------------dfs---------------*/ inline void dfs(int u,int f) {deep[u]=deep[f]+1;in[u]=++sign;pre[sign]=u;for(int i=head[u];i!=-1;i=e[i].next){int to=e[i].to;if(to==f) continue;dfs(to,u);}out[u]=sign; } /*-----------------線段樹-----------------*/ inline void pushdown(int cur) {if(p[cur].lazy1){p[cur<<1].lazy1+=p[cur].lazy1;p[cur<<1].lazy1%=mod;p[cur<<1|1].lazy1+=p[cur].lazy1;p[cur<<1|1].lazy1%=mod;p[cur<<1].sum=(p[cur<<1].sum+p[cur].lazy1*(p[cur<<1].r-p[cur<<1].l+1)%mod+mod)%mod;p[cur<<1|1].sum=(p[cur<<1|1].sum+p[cur].lazy1*(p[cur<<1|1].r-p[cur<<1|1].l+1)%mod+mod)%mod;p[cur].lazy1=0;}if(p[cur].lazy2){p[cur<<1].lazy2+=p[cur].lazy2;p[cur<<1].lazy2%=mod;p[cur<<1|1].lazy2+=p[cur].lazy2;p[cur<<1|1].lazy2%=mod;p[cur].lazy2=0;} } inline void build(int l,int r,int cur) {p[cur].l=l;p[cur].r=r;p[cur].lazy1=p[cur].lazy2=p[cur].sum=0;if(l==r) return ;int mid=l+r>>1;build(l,mid,cur<<1);build(mid+1,r,cur<<1|1); } inline void update(int l,int r,ll v,ll k,int cur) {int L=p[cur].l;int R=p[cur].r;if(l<=L&&R<=r){p[cur].sum=(p[cur].sum+v*(R-L+1)%mod+mod)%mod;p[cur].lazy1=(p[cur].lazy1+v+mod)%mod;p[cur].lazy2=(p[cur].lazy2+k+mod)%mod;return ;}pushdown(cur);int mid=L+R>>1;if(r<=mid) update(l,r,v,k,cur<<1);else if(l>mid) update(l,r,v,k,cur<<1|1);else{update(l,mid,v,k,cur<<1);update(mid+1,r,v,k,cur<<1|1);} } inline ll query(int pos,int cur) {int L=p[cur].l;int R=p[cur].r;if(L==R) return (p[cur].sum+deep[pre[L]]*p[cur].lazy2%mod+mod)%mod;//到達所要求的節點的時候,不要忘了加上和這個點深度有關的那一部分值。pushdown(cur);int mid=L+R>>1;if(pos<=mid) return query(pos,cur<<1);else return query(pos,cur<<1|1); } int main() {int t,x,op;ll v,k;read(t);while(t--){init();read(n);for(int i=2;i<=n;i++){read(x);add(i,x);add(x,i);}deep[0]=-1;dfs(1,0);build(1,n,1);read(m);while(m--){read(op);if(op==1){read(x);read1(v);read1(k);update(in[x],out[x],deep[x]*k+v,-k,1);}else if(op==2) {read(x);printf("%I64d\n",query(in[x],1));}}}return 0; }

努力加油a啊,(o)/~

總結

以上是生活随笔為你收集整理的Change FZU - 2277(线段树+dfs序)的全部內容,希望文章能夠幫你解決所遇到的問題。

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