HDU 5044 Tree 树链剖分
Tree
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
【Problem Description】
You are given a tree (an acyclic undirected connected graph) with N nodes. The tree nodes are numbered from 1 to N
There are N - 1 edges numbered from 1 to N - 1.
Each node has a value and each edge has a value. The initial value is 0.
There are two kind of operation as follows:
● ADD1 u v k: for nodes on the path from u to v, the value of these nodes increase by k.
● ADD2 u v k: for edges on the path from u to v, the value of these edges increase by k.
After finished M operation on the tree, please output the value of each node and edge.
There are N - 1 edges numbered from 1 to N - 1.
Each node has a value and each edge has a value. The initial value is 0.
There are two kind of operation as follows:
● ADD1 u v k: for nodes on the path from u to v, the value of these nodes increase by k.
● ADD2 u v k: for edges on the path from u to v, the value of these edges increase by k.
After finished M operation on the tree, please output the value of each node and edge.
【Input】
The first line of the input is T (1 ≤ T ≤ 20), which stands for the number of test cases you need to solve.
The first line of each case contains two integers N ,M (1 ≤ N, M ≤105),denoting the number of nodes and operations, respectively.
The next N - 1 lines, each lines contains two integers u, v(1 ≤ u, v ≤ N ), denote there is an edge between u,v and its initial value is 0.
For the next M line, contain instructions “ADD1 u v k” or “ADD2 u v k”. (1 ≤ u, v ≤ N, -105 ≤ k ≤ 105)
The first line of each case contains two integers N ,M (1 ≤ N, M ≤105),denoting the number of nodes and operations, respectively.
The next N - 1 lines, each lines contains two integers u, v(1 ≤ u, v ≤ N ), denote there is an edge between u,v and its initial value is 0.
For the next M line, contain instructions “ADD1 u v k” or “ADD2 u v k”. (1 ≤ u, v ≤ N, -105 ≤ k ≤ 105)
【Output】
For each test case, print a line “Case #t:”(without quotes, t means the index of the test case) at the beginning.
The second line contains N integer which means the value of each node.
The third line contains N - 1 integer which means the value of each edge according to the input order.
The second line contains N integer which means the value of each node.
The third line contains N - 1 integer which means the value of each edge according to the input order.
【Sample Input】
2 4 2 1 2 2 3 2 4 ADD1 1 4 1 ADD2 3 4 2 4 2 1 2 2 3 1 4 ADD1 1 4 5 ADD2 3 2 4
【Sample Output】
Case #1: 1 1 0 1 0 2 2 Case #2: 5 0 0 5 0 4 0
【题意】
维护一棵树,操作是对某两点路径上的所有点的权值加上某个值,或者对某两点路径上的所有边的权值加上某个值。
【分析】
Kuang神出题的时候特别为这题卡了数据,LCT目测是不够过的,用树链剖分转成线性加输入挂也是勉强过,4700ms左右,那种1000~2000ms左右的算法不太明白是怎么写的。
1.维护两点路径上的点权值是树链剖分的基本操作
2.维护两点路径上的边权值需要在剖分的时候直接按照边的情况,直接用子结点的序号来代表一条边,然后做好边原本序号的记录
一般的树链剖分是直接用树状数组,但是由于本题的最终结果要求的是输出所有点和所有边的权值,因此采用树状数组每次求一次sum来得到每个点的值就有点浪费效率了。
可以参考原本树状数组的方式,直接用一个普通的数组来记录情况,在起点+value,在终点后的一个点-value,表示对整段线段完成加权值;最终求和的时候只需要从头向后扫一遍,求出每个点的sum(i)即可
1 /* *********************************************** 2 MYID : Chen Fan 3 LANG : G++ 4 PROG : HDU 5044 5 ************************************************ */ 6 7 #include <iostream> 8 #include <cstdio> 9 #include <cstring> 10 #include <algorithm> 11 12 using namespace std; 13 14 #define MAXN (int)1E5+10 15 #define MAXM (int)2E5+10 16 17 int son[MAXN],ans[MAXN]; 18 int father[MAXN],size[MAXN],level[MAXN],data[MAXN],top[MAXN]; 19 int start[MAXN]; 20 21 typedef struct nod 22 { 23 int to,next,no; 24 } node; 25 node edge[MAXM]; 26 int last,n; 27 28 void addedge(int from,int to,int k) 29 { 30 last++; 31 edge[last].to=to; 32 edge[last].next=start[from]; 33 edge[last].no=k; 34 start[from]=last; 35 } 36 37 int c[MAXN],pos[MAXN],fp[MAXN]; 38 int ec[MAXN],epos[MAXN],fep[MAXN]; 39 int tot; 40 41 int q[MAXN]; 42 void bfs() 43 { 44 int head=1,tail=1; 45 q[1]=1; 46 level[1]=0; 47 father[1]=0; 48 49 while(head<=tail) 50 { 51 int now=q[head]; 52 size[now]=1; 53 for (int i=start[now];i;i=edge[i].next) 54 { 55 int temp=edge[i].to; 56 if (temp!=father[now]) 57 { 58 father[temp]=now; 59 fep[temp]=edge[i].no; 60 level[temp]=level[now]+1; 61 tail++; 62 q[tail]=temp; 63 } 64 } 65 head++; 66 } 67 for (int i=n;i>=1;i--) 68 { 69 int now=q[i]; 70 if (father[now]) 71 { 72 size[father[now]]+=size[now]; 73 if (son[father[now]]==0||size[now]>size[son[father[now]]]) 74 son[father[now]]=now; 75 } 76 } 77 for (int i=1;i<=n;i++) 78 { 79 int now=q[i]; 80 if (son[father[now]]==now) top[now]=top[father[now]]; 81 else 82 { 83 top[now]=now; 84 while(now) 85 { 86 tot++; 87 pos[now]=tot; 88 fp[tot]=now; 89 now=son[now]; 90 } 91 } 92 } 93 } 94 95 void change(int x,int y,int value) 96 { 97 while(top[x]!=top[y]) 98 { 99 if (level[top[x]]<level[top[y]]) swap(x,y); 100 101 c[pos[top[x]]]+=value; 102 c[pos[x]+1]-=value; 103 104 x=father[top[x]]; 105 } 106 if (level[x]>level[y]) swap(x,y); 107 108 c[pos[x]]+=value; 109 c[pos[y]+1]-=value; 110 } 111 112 void change_edge(int x,int y,int value) 113 { 114 while(top[x]!=top[y]) 115 { 116 if (level[top[x]]<level[top[y]]) swap(x,y); 117 118 ec[pos[top[x]]]+=value; 119 ec[pos[x]+1]-=value; 120 121 x=father[top[x]]; 122 } 123 if (level[x]>level[y]) swap(x,y); 124 125 ec[pos[son[x]]]+=value; 126 ec[pos[y]+1]-=value; 127 } 128 129 int INT() { 130 char ch; 131 int res; 132 bool neg; 133 while (ch = getchar(), !isdigit(ch) && ch != '-') 134 ; 135 if (ch == '-') { 136 neg = true; 137 res = 0; 138 } else { 139 neg = false; 140 res = ch - '0'; 141 } 142 while (ch = getchar(), isdigit(ch)) 143 res = res * 10 + ch - '0'; 144 return neg ? -res : res; 145 } 146 147 int main() 148 { 149 freopen("5044.txt","r",stdin); 150 151 int t; 152 t=INT(); 153 154 for (int tt=1;tt<=t;tt++) 155 { 156 printf("Case #%d:\n",tt); 157 158 int m; 159 n=INT();m=INT(); 160 161 memset(start,0,sizeof(start)); 162 last=0; 163 for (int i=1;i<n;i++) 164 { 165 int u,v; 166 u=INT(); 167 v=INT(); 168 addedge(u,v,i); 169 addedge(v,u,i); 170 } 171 172 memset(son,0,sizeof(son)); 173 tot=0; 174 bfs(); 175 176 memset(c,0,sizeof(c)); 177 memset(ec,0,sizeof(ec)); 178 179 for (int i=1;i<=m;i++) 180 { 181 char s; 182 int c1,c2,k; 183 s=getchar(); 184 while (!isdigit(s)) s=getchar(); 185 c1=INT(); 186 c2=INT(); 187 k=INT(); 188 if (s=='1') change(c1,c2,k); 189 else change_edge(c1,c2,k); 190 } 191 192 int ss=0; 193 for (int i=1;i<=n;i++) 194 { 195 ss+=c[i]; 196 ans[fp[i]]=ss; 197 } 198 printf("%d",ans[1]); 199 for (int i=2;i<=n;i++) 200 { 201 putchar(' '); 202 printf("%d",ans[i]); 203 } 204 putchar('\n'); 205 206 ss=0; 207 for (int i=1;i<=n;i++) 208 { 209 ss+=ec[i]; 210 ans[fep[fp[i]]]=ss; 211 } 212 if (n>1) printf("%d",ans[1]); 213 for (int i=2;i<n;i++) 214 { 215 putchar(' '); 216 printf("%d",ans[i]); 217 } 218 putchar('\n'); 219 220 } 221 222 return 0; 223 }
Do Cool Things That Matter!