2014-10-10 22:37:06
思路:这题给树链剖分学习的第一个阶段画上了一个句号,一开始看的时候线段树乱搞都没搞出来 orz。后来看了结题报告发现自己 too young。
首先把点构成的树剖分是没有悬念的,接下来如果直接用线段树搞的话,节点维护什么呢?每种颜色及其次数吗?显然不行。转换下思路,这题其实和上海网赛的那题有点像,只不过这题少了边处理,只有点处理。由于算法可以离线,更新次数多,但查询只有一次(即:最后把所有点的信息输出),所以可以把更新操作(树上路径更新)用树剖转化为线性结构上的更新操作!这个转化其实就是树链剖分算法思想的最好体现。所以对每个更新如:[a,b],c ,用两个标记记录 f[a] += c , f[b + 1] -= c,因为要记录所有 c ,所以 f[]可以是向量数组,f[a].push_back(c) , f[b + 1].push_back(-c),最后扫一遍点就出来了。
1 /************************************************************************* 2 > File Name: 5029.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Fri 10 Oct 2014 08:34:44 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <queue> 16 #include <iostream> 17 #include <algorithm> 18 using namespace std; 19 #define lp (p << 1) 20 #define rp (p << 1|1) 21 #define getmid(l,r) (l + (r - l) / 2) 22 #define MP(a,b) make_pair(a,b) 23 typedef long long ll; 24 const int INF = 1 << 30; 25 const int maxn = 100010; 26 27 inline int Read(){ 28 int x = 0; 29 char c = getchar(); 30 while(c < '0' || c > '9') c = getchar(); 31 while(c >= '0' && c <= '9'){ x = x * 10 + c - '0'; c = getchar();} 32 return x; 33 } 34 35 int n,m; 36 int first[maxn],next[maxn << 1],ver[maxn << 1],ecnt; 37 int dep[maxn],sz[maxn],son[maxn],fa[maxn],top[maxn],w[maxn],aw[maxn],tsz; 38 int tmax[maxn << 2],col[maxn << 2],ans[maxn]; 39 vector<int> f[maxn]; 40 41 void Init(){ 42 for(int i = 1; i <= n; ++i) f[i].clear(); 43 memset(col,0,sizeof(col)); 44 memset(tmax,0,sizeof(tmax)); 45 memset(first,-1,sizeof(first)); 46 ecnt = tsz = 0; 47 } 48 49 void Add_edge(int u,int v){ 50 next[++ecnt] = first[u]; 51 ver[ecnt] = v; 52 first[u] = ecnt; 53 } 54 55 void Dfs(int p,int pre,int d){ 56 sz[p] = 1; 57 son[p] = -1; 58 fa[p] = pre; 59 dep[p] = d; 60 int v,tmp = 0; 61 for(int i = first[p]; i != -1; i = next[i]) if((v = ver[i]) != pre){ 62 Dfs(v,p,d + 1); 63 if(sz[v] > tmp){ 64 tmp = sz[v]; 65 son[p] = v; 66 } 67 sz[p] += sz[v]; 68 } 69 } 70 71 void Dfs_pos(int p,int tp){ 72 w[p] = ++tsz; 73 aw[tsz] = p; 74 top[p] = tp; 75 if(son[p] != -1) Dfs_pos(son[p],tp); 76 for(int i = first[p]; i != -1; i = next[i]){ 77 int v = ver[i]; 78 if(v != son[p] && v != fa[p]) 79 Dfs_pos(v,v); 80 } 81 } 82 83 void Change(int a,int b,int c){ 84 int f1 = top[a],f2 = top[b]; 85 while(f1 != f2){ 86 if(dep[f1] > dep[f2]){ 87 swap(a,b); 88 swap(f1,f2); 89 } 90 f[w[f2]].push_back(c); 91 f[w[b] + 1].push_back(-c); 92 b = fa[f2]; 93 f2 = top[b]; 94 } 95 if(dep[a] > dep[b]) swap(a,b); 96 f[w[a]].push_back(c); 97 f[w[b] + 1].push_back(-c); 98 } 99 100 void Update_tree(int a,int c,int p,int l,int r){ 101 if(l == r){ 102 tmax[p] += c; 103 if(tmax[p] > 0) col[p] = l; 104 else col[p] = 0; 105 return; 106 } 107 int mid = getmid(l,r); 108 if(a <= mid) Update_tree(a,c,lp,l,mid); 109 else Update_tree(a,c,rp,mid + 1,r); 110 if(tmax[lp] >= tmax[rp]){ 111 tmax[p] = tmax[lp]; 112 col[p] = col[lp]; 113 } 114 else{ 115 tmax[p] = tmax[rp]; 116 col[p] = col[rp]; 117 } 118 } 119 120 int main(){ 121 int a,b,c; 122 while(1){ 123 n = Read(),m = Read(); 124 if(!n && !m) break; 125 Init(); 126 for(int i = 1; i < n; ++i){ 127 a = Read(),b = Read(); 128 Add_edge(a,b); 129 Add_edge(b,a); 130 } 131 Dfs(1,0,0); 132 Dfs_pos(1,1); 133 for(int i = 1; i <= m; ++i){ 134 a = Read(); 135 b = Read(); 136 c = Read(); 137 Change(a,b,c); 138 } 139 for(int i = 1; i <= n; ++i){ 140 for(unsigned int j = 0; j < f[i].size(); ++j) 141 Update_tree(abs(f[i][j]),f[i][j] > 0 ? 1 : -1,1,1,maxn); 142 ans[aw[i]] = col[1]; 143 } 144 for(int i = 1; i <= n; ++i) 145 printf("%d\n",ans[i]); 146 } 147 return 0; 148 }