[luogu4556][Vani有約會]
阿新 • • 發佈:2018-12-10
題目連結
吐槽
這道題調了7個小時也是夠了。最後只好比著題解做了一遍2333
思路
首先考慮n=2000的情況。因為這是在一條路徑上,所以可以考慮差分。用a[i][j]表示第i個點中j這種糧食出現的次數。加入要在從x到y的路徑上加入c這種糧食。將這條路徑分為兩部分進行差分。從x到lca,也就是將a[x][c]++,a[fa[lca]]--。從y到son[lca]。就是將a[y][c]++,a[lca]--。(詳細原因見樹上差分)最後dfs一遍,並且在回溯的時候合併一下就行了。
那麼對於n=100000的資料,只要用線段樹合併優化一下就行了。也就是將a陣列改為n棵動態開點線段樹。合併的時候用線段樹合併的板子合併一下就行了。
程式碼
/* * @Author: wxyww * @Date: 2018-12-10 14:37:11 * @Last Modified time: 2018-12-10 21:15:06 */ #include<cstdio> #include<iostream> #include<vector> using namespace std; typedef long long ll; #define Ls TR[cur].ls #define Rs TR[cur].rs ll read() { ll x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } const int N = 100000 + 100,logN = 20; struct node { int ls,rs,ans,sum; }TR[N * 50]; int n,m,dep[N],lca[N][logN + 30],root[N]; vector<int>e[N]; int num; void get_lca(int u,int father) { for(int i = 1;i < logN;++i) lca[u][i] = lca[lca[u][i - 1]][i - 1]; int k = e[u].size(); for(int i = 0;i < k;++i) { int v = e[u][i]; if(v == father) continue; lca[v][0] = u; dep[v] = dep[u] + 1; get_lca(v,u); } } int LCA(int x,int y) { if(dep[x] < dep[y]) swap(x,y); for(int i = logN - 1;i >= 0;--i) if(dep[lca[x][i]] >= dep[y]) x = lca[x][i]; if(x == y) return y; for(int i = logN - 1;i >= 0;--i) { if(lca[x][i] != lca[y][i]) { x = lca[x][i];y = lca[y][i]; } } return lca[x][0]; } void up(int cur) { if(TR[Ls].sum >= TR[Rs].sum) { TR[cur].sum = TR[Ls].sum; TR[cur].ans = TR[Ls].ans; } else { TR[cur].sum = TR[Rs].sum; TR[cur].ans = TR[Rs].ans; } } void update(int &cur,int l,int r,int pos,int c) { if(!cur) cur = ++num; if(l == r) { TR[cur].sum += c; TR[cur].ans = l; return; } int mid = (l + r) >> 1; if(pos <= mid) update(Ls,l,mid,pos,c); else update(Rs,mid + 1,r,pos,c); up(cur); } int merge(int cur,int a,int l,int r) { if(!cur) return a; if(!a) return cur; if(l == r) { TR[cur].sum += TR[a].sum; TR[cur].ans = l; return cur; } int mid = (l + r) >> 1; Ls = merge(Ls,TR[a].ls,l,mid); Rs = merge(Rs,TR[a].rs,mid + 1,r); up(cur); return cur; } void dfs(int u,int father) { int k = e[u].size(); for(int i = 0;i < k;++i) { int v = e[u][i]; if(v == father) continue; dfs(v,u); merge(root[u],root[v],1,N - 100); } } int main() { int n = read(),m = read(); for(int i = 1;i < n;++i) { int x = read(),y = read(); e[x].push_back(y); e[y].push_back(x); } dep[1] = 1; for(int i = 1;i <= n;++i) root[i] = ++num; get_lca(1,0); while(m--) { int x = read(),y = read(),c = read(); int K = LCA(x,y); update(root[x],1,N - 100,c,1); update(root[y],1,N - 100,c,1); update(root[K],1,N - 100,c,-1); if(lca[K][0]) update(root[lca[K][0]],1,N - 100,c,-1); } dfs(1,0); for(int i = 1;i <= n;++i) { if(TR[root[i]].sum == 0) puts("0"); else printf("%d\n",TR[root[i]].ans); } return 0; }