以下問題均允許離線,根節點都為1。
prob1 : 一棵有根樹,要求線性時間求出任意子樹的權值和。
prob2 : 一顆有根樹,要求O(nlogn)求出與u距離不超過x且在u子樹中的節點的權值和。
prob3 : 一顆有根樹,要求O(nlogn)求出與u距離不超過x且在u子樹中的不同顏色種類個數,顏色數不超過1E6。
prob4 : 一顆有根數,要求O(nlogn+大常數)求出與u距離不超過x且在u子樹中的權值的lcm取模,節點的值不超過1E6,質因子不超過1E4。TIPS:取模後傳統公式顯然不成立。
(未填完)
Prob 1
這個問題很簡單吧,找個dfs序做個字首和就可以了。
但是dfs序卻是很有用的。
沒有程式碼。
Prob 2
有了限制,但我們注意到這個問題只是詢問某個節點往下深度不超過x的權值和。
沿用prob1的思想,我們仍然想用字首和,而一個節點的貢獻與他的深度有關。
因此我們以深度為下標,按照dfs序依次加入可持久化線段樹中,就能計算答案了。
實現太簡單,沒有程式碼。
Prob 3
樹的問題太難了,我們先想鏈上問題怎麼做。
現在問題的關鍵在於,會有重複的計數,因此我們要消除這個影響。
將詢問離線下來,按照詢問右端點排序,依次加入每一個點。若該點與前面有重複的,在前面的位置上減去1的貢獻。
這樣就轉換為單點修改,區間查詢,樹狀陣列即可。
樹上也同樣,先求出dfs序,將詢問按deppos+x排序,再依次加入每一個點。若這個點與前面的有重複,要在所有與它重複的點lca離他距離最近處減去1的貢獻。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1E6+5; 4 const int inf=INT_MAX; 5 int head[maxn*2],size,dfn[maxn],ti,back[maxn],fa[maxn][21],last[maxn],c[maxn],n,m,dep[maxn],ans[maxn],x,y,maxD; 6 struct edge{int to,next;}E[maxn*2]; 7 struct BIT 8 { 9 int t[maxn]; 10 int lowbit(int x){return x&-x;} 11 void add(int x,int y){while(x<=n){t[x]+=y;x+=lowbit(x);}} 12 int ask(int x){int ans=0;while(x){ans+=t[x];x-=lowbit(x);}return ans;} 13 }T; 14 struct query{int pos,d,num;}Q[maxn]; 15 vector<int>bel[maxn]; 16 set<int>pre[maxn]; 17 bool cmp(query x,query y){return dep[x.pos]+x.d<dep[y.pos]+y.d;} 18 void add(int u,int v) 19 { 20 E[++size].to=v; 21 E[size].next=head[u]; 22 head[u]=size; 23 } 24 void dfs(int u,int F,int d) 25 { 26 maxD=max(maxD,d); 27 fa[u][0]=F; 28 bel[d].push_back(u); 29 dfn[u]=++ti; 30 last[u]=back[ti]=u; 31 dep[u]=d; 32 for(int i=head[u];i;i=E[i].next) 33 { 34 int v=E[i].to; 35 if(v==F)continue; 36 dfs(v,u,d+1); 37 last[u]=last[v]; 38 } 39 } 40 void init() 41 { 42 for(int i=1;i<=20;++i) 43 for(int u=1;u<=n;++u)fa[u][i]=fa[fa[u][i-1]][i-1]; 44 } 45 int lca(int x,int y) 46 { 47 if(dep[x]<dep[y])swap(x,y); 48 int d=dep[x]-dep[y]; 49 for(int i=0;i<=20;++i) 50 if(d&(1<<i))x=fa[x][i]; 51 if(x==y)return x; 52 for(int i=20;i>=0;--i) 53 if(fa[x][i]!=fa[y][i]) 54 { 55 x=fa[x][i]; 56 y=fa[y][i]; 57 } 58 return fa[x][0]; 59 } 60 void insert(int x,int num) 61 { 62 T.add(num,1); 63 if(pre[x].size()==0) 64 { 65 pre[x].insert(num); 66 pre[x].insert(inf); 67 pre[x].insert(-1); 68 } 69 else 70 { 71 set<int>::iterator pr=pre[x].lower_bound(num); 72 set<int>::iterator pl=pr; 73 --pl; 74 num=back[num];//特別注意這裡,此時的num已經是節點的編號而不是dfn序了 75 if(*pl==-1)T.add(dfn[lca(back[*pr],num)],-1); 76 else if(*pr==inf)T.add(dfn[lca(back[*pl],num)],-1); 77 else 78 { 79 int u=back[*pl],v=back[*pr]; 80 int l1=lca(u,num),l2=lca(v,num); 81 if(dep[l1]>dep[l2]) T.add(dfn[l1],-1); 82 else T.add(dfn[l2],-1); 83 } 84 pre[x].insert(dfn[num]); 85 } 86 } 87 int main() 88 { 89 ios::sync_with_stdio(false); 90 cin>>n>>m; 91 for(int i=1;i<=n;++i)cin>>c[i]; 92 for(int i=1;i<=n-1;++i) 93 { 94 cin>>x>>y; 95 add(x,y); 96 add(y,x); 97 } 98 dfs(1,1,1); 99 init(); 100 for(int i=1;i<=m;++i) 101 { 102 cin>>Q[i].pos>>Q[i].d; 103 Q[i].num=i; 104 } 105 sort(Q+1,Q+m+1,cmp); 106 int pos=1; 107 for(int i=1;i<=n;++i) 108 { 109 for(int j=0;j<bel[i].size();++j) 110 { 111 int u=bel[i][j]; 112 insert(c[u],dfn[u]); 113 } 114 while(pos<=m&&min(dep[Q[pos].pos]+Q[pos].d,maxD)==i) 115 { 116 ans[Q[pos].num]=T.ask(dfn[last[Q[pos].pos]])-T.ask(dfn[Q[pos].pos]-1); 117 ++pos; 118 } 119 } 120 for(int i=1;i<=m;++i)cout<<ans[i]<<endl; 121 return 0; 122 }
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1E5+5; 4 int n,m,head[maxn*2],size,x,y,fa[maxn],c[maxn]; 5 set<int>ans; 6 struct edge{int to,next;}E[maxn*2]; 7 void add(int u,int v) 8 { 9 E[++size].to=v; 10 E[size].next=head[u]; 11 head[u]=size; 12 } 13 void init(int u,int F) 14 { 15 fa[u]=F; 16 for(int i=head[u];i;i=E[i].next) 17 { 18 int v=E[i].to; 19 if(v==F)continue; 20 init(v,u); 21 } 22 } 23 void dfs(int u,int F,int d) 24 { 25 ans.insert(c[u]); 26 if(d==0)return; 27 for(int i=head[u];i;i=E[i].next) 28 { 29 int v=E[i].to; 30 if(v==F)continue; 31 dfs(v,u,d-1); 32 } 33 } 34 int main() 35 { 36 ios::sync_with_stdio(false); 37 cin>>n>>m; 38 for(int i=1;i<=n;++i)cin>>c[i]; 39 for(int i=1;i<=n-1;++i) 40 { 41 cin>>x>>y; 42 add(x,y); 43 add(y,x); 44 } 45 init(1,1); 46 while(m--) 47 { 48 cin>>x>>y; 49 ans.clear(); 50 dfs(x,fa[x],y); 51 cout<<ans.size()<<endl; 52 } 53 return 0; 54 }
(未填完)
Prob 4
樹的問題太難了,我們先想鏈上問題怎麼做。
鏈上問題還是太難了,我們先考慮只有質數怎麼做。
只有質數的話,就轉化為Prob3了。
再考慮鏈上一般的情況。我們只要把每個數質因式分解,對於固定的質數p以及它的次數k,看將它看做1~k種顏色的“和”。如:
其餘的類似。
這樣繼續沿用Prob3,可以推廣到樹上。開個set就行了。
程式碼看博主心情。