mjt 树
\(mjt樹\)
題目背景
從前森林里有一棵很大的\(mjt\)樹,樹上有很多小動物。
題目描述
mjt樹上有 \(n\) 個房間,第 i 個房間住著\(a_i\) 只第bi 種小動物。
這\(n\)個房間用\(n-1\)條路連接起來,其中房間1位\(mjt\)樹的根。
現在每個房間\(x\)的小動物想知道,以房間x為根的\(mjt\)樹中有多少只它們的同類.
輸入輸出格式
輸入格式:
第一行一個整數n,表示房間數
接下來\(n\)行,每行兩個整數\(a_i,b_i\)。
再之后\(n-1\)行,每行兩個整數\(x,y\),表示x和y之間有一條路徑
輸出格式:
一行n個數,第\(i\)個數表示以房間i為根的\(mjt\)樹中\(b_i\)種小動物有多少只,兩個數之間用空格隔開
輸入輸出樣例
輸入樣例#1:
5
2 1
3 1
4 2
5 1
6 2
1 2
1 3
3 4
3 5
輸出樣例#1:
10 3 10 5 6
說明
\(b_i\leq n\leq 100000,a_i\leq 1000\)
by xjjppm.
這個題好像是“理責慨”理叔出的
但是為什么叫“燜箭筒”樹我還真不知道
我YY了三個做法
有兩種做法能A這道題
首先題目將所有點劃分成許多種類
所以我用顏色代替
做法1:
DFS中找到每個點所有的與其顏色相同的所有祖先 在祖先中加上這個點的權值 缺陷:太慢做法2:
將每個點的權值加到其最近的祖先處 然后在回溯的時候就會逐步加到其所有祖先處 查詢很快 如果整棵樹是比較均衡的樹 那么速度就會還不錯 缺陷:很容易被卡做法3:
在DFS的時候處理正在遍歷的鏈上的所有顏色的節點 這樣就可以O(1)找出其最近祖先 同樣是將權值加到最近祖先處 速度和DFS遍歷樹的速度差不多 能非??焖俚耐ㄟ^該題做法1
#include<iostream> #include<cstdio> #define N 1000005 using namespace std;struct node{int next,v; }edge[N]; int head[N],sum;void add(int a,int b){edge[++sum].v=b;edge[sum].next=head[a];head[a]=sum;edge[++sum].v=a;edge[sum].next=head[b];head[b]=sum; }int n; int fa[N]; int ans[N]; int zhong[N]; int duosh[N];int find(int s){int father=fa[s];while(father){ans[father]+=(zhong[s]==zhong[father])*duosh[s];father=fa[father];}ans[s]+=duosh[s]; }void DFS(int s,int fath){fa[s]=fath;find(s);for(int i=head[s];i;i=edge[i].next){if(edge[i].v==fa[s])continue;DFS(edge[i].v,s);} }int main(){cin>>n;for(int i=1;i<=n;++i)scanf("%d%d",&duosh[i],&zhong[i]);for(int i=1;i<n;++i){int a,b;scanf("%d%d",&a,&b);add(a,b);}DFS(1,0);for(int i=1;i<=n;++i)cout<<ans[i]<<' ';return 0; }做法2
#include<iostream> #include<cstdio> #define N 200010 using namespace std;struct node{int next,v; }edge[N]; int head[N],sum;void add(int a,int b){edge[++sum].v=b;edge[sum].next=head[a];head[a]=sum;edge[++sum].v=a;edge[sum].next=head[b];head[b]=sum; }int n; int fa[N]; int ans[N]; int zhong[N]; int duosh[N];int find(int s){int father=fa[s];while(father){if(zhong[s]==zhong[father]){ans[father]+=ans[s];return 0;}father=fa[father];} }void DFS(int s,int fath){fa[s]=fath;for(int i=head[s];i;i=edge[i].next){if(edge[i].v==fa[s])continue;DFS(edge[i].v,s);}find(s); }int main(){scanf("%d",&n);for(int i=1;i<=n;++i)scanf("%d%d",&duosh[i],&zhong[i]);for(int i=1;i<n;++i){int a,b;scanf("%d%d",&a,&b);add(a,b);}for(int i=1;i<=n;++i)ans[i]=duosh[i];DFS(1,0);for(int i=1;i<=n;++i)printf("%d ",ans[i]);return 0; }做法3
#include<iostream> #include<cstdio> #define N 1000010 using namespace std;struct node{int next,v; }edge[N]; int head[N],sum;void add(int a,int b){edge[++sum].v=b;edge[sum].next=head[a];head[a]=sum;edge[++sum].v=a;edge[sum].next=head[b];head[b]=sum; }int n; int fa[N]; int ans[N]; int zhong[N]; int duosh[N];int ff[N];//顏色為i的點最后一次出現的位置 int color[N];void DFS(int s,int fath){fa[s]=fath;int fn=ff[zhong[s]];ff[zhong[s]]=s;for(int i=head[s];i;i=edge[i].next){if(edge[i].v==fa[s])continue;DFS(edge[i].v,s);}ans[fn]+=ans[s];ff[zhong[s]]=fn; }int main(){scanf("%d",&n);for(int i=1;i<=n;++i)scanf("%d%d",&duosh[i],&zhong[i]);for(int i=1;i<n;++i){int a,b;scanf("%d%d",&a,&b);add(a,b);}for(int i=1;i<=n;++i)ans[i]=duosh[i];DFS(1,0);for(int i=1;i<=n;++i)printf("%d ",ans[i]);return 0; }轉載于:https://www.cnblogs.com/qdscwyy/p/7739228.html
總結
- 上一篇: 敏捷冲刺每日报告一(Java-Team)
- 下一篇: Jzoj4790 选数问题