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.
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)
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.
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 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std;#define MAXN (int)1E5+10 #define MAXM (int)2E5+10 int son[MAXN],ans[MAXN];int father[MAXN],size[MAXN],level[MAXN],data[MAXN],top[MAXN];int start[MAXN];typedef struct nod { int to,next,no; } node; node edge[MAXM]; int last,n;void addedge (int from,int to,int k) { last++; edge[last].to=to; edge[last].next=start[from]; edge[last].no=k; start[from]=last; } int c[MAXN],pos[MAXN],fp[MAXN];int ec[MAXN],epos[MAXN],fep[MAXN];int tot;int q[MAXN];void bfs () { int head=1 ,tail=1 ; q[1 ]=1 ; level[1 ]=0 ; father[1 ]=0 ; while (head<=tail) { int now=q[head]; size[now]=1 ; for (int i=start[now];i;i=edge[i].next) { int temp=edge[i].to; if (temp!=father[now]) { father[temp]=now; fep[temp]=edge[i].no; level[temp]=level[now]+1 ; tail++; q[tail]=temp; } } head++; } for (int i=n;i>=1 ;i--) { int now=q[i]; if (father[now]) { size[father[now]]+=size[now]; if (son[father[now]]==0 ||size[now]>size[son[father[now]]]) son[father[now]]=now; } } for (int i=1 ;i<=n;i++) { int now=q[i]; if (son[father[now]]==now) top[now]=top[father[now]]; else { top[now]=now; while (now) { tot++; pos[now]=tot; fp[tot]=now; now=son[now]; } } } } void change (int x,int y,int value) { while (top[x]!=top[y]) { if (level[top[x]]<level[top[y]]) swap (x,y); c[pos[top[x]]]+=value; c[pos[x]+1 ]-=value; x=father[top[x]]; } if (level[x]>level[y]) swap (x,y); c[pos[x]]+=value; c[pos[y]+1 ]-=value; } void change_edge (int x,int y,int value) { while (top[x]!=top[y]) { if (level[top[x]]<level[top[y]]) swap (x,y); ec[pos[top[x]]]+=value; ec[pos[x]+1 ]-=value; x=father[top[x]]; } if (level[x]>level[y]) swap (x,y); ec[pos[son[x]]]+=value; ec[pos[y]+1 ]-=value; } int INT () { char ch; int res; bool neg; while (ch = getchar (), !isdigit (ch) && ch != '-' ) ; if (ch == '-' ) { neg = true ; res = 0 ; } else { neg = false ; res = ch - '0' ; } while (ch = getchar (), isdigit (ch)) res = res * 10 + ch - '0' ; return neg ? -res : res; } int main () { freopen ("5044.txt" ,"r" ,stdin); int t; t=INT (); for (int tt=1 ;tt<=t;tt++) { printf ("Case #%d:\n" ,tt); int m; n=INT ();m=INT (); memset (start,0 ,sizeof (start)); last=0 ; for (int i=1 ;i<n;i++) { int u,v; u=INT (); v=INT (); addedge (u,v,i); addedge (v,u,i); } memset (son,0 ,sizeof (son)); tot=0 ; bfs (); memset (c,0 ,sizeof (c)); memset (ec,0 ,sizeof (ec)); for (int i=1 ;i<=m;i++) { char s; int c1,c2,k; s=getchar (); while (!isdigit (s)) s=getchar (); c1=INT (); c2=INT (); k=INT (); if (s=='1' ) change (c1,c2,k); else change_edge (c1,c2,k); } int ss=0 ; for (int i=1 ;i<=n;i++) { ss+=c[i]; ans[fp[i]]=ss; } printf ("%d" ,ans[1 ]); for (int i=2 ;i<=n;i++) { putchar (' ' ); printf ("%d" ,ans[i]); } putchar ('\n' ); ss=0 ; for (int i=1 ;i<=n;i++) { ss+=ec[i]; ans[fep[fp[i]]]=ss; } if (n>1 ) printf ("%d" ,ans[1 ]); for (int i=2 ;i<n;i++) { putchar (' ' ); printf ("%d" ,ans[i]); } putchar ('\n' ); } return 0 ; }