1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 11858 Solved: 4803
[Submit][Status][Discuss]
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
1
2
2
10
6
5
6
5
16
HINT
Source
预处理
第一遍dfs求出树每个结点的深度deep[x],其为根的子树大小size[x]
以及祖先的信息fa[x][i]表示x往上距离为2^i的祖先
第二遍dfs
根节点为起点,向下拓展构建重链
选择最大的一个子树的根继承当前重链
其余节点,都以该节点为起点向下重新拉一条重链
给每个结点分配一个位置编号,每条重链就相当于一段区间,用数据结构去维护。
把所有的重链首尾相接,放到同一个数据结构上,然后维护这一个整体即可
修改操作
1、单独修改一个点的权值
根据其编号直接在数据结构中修改就行了。
2、修改点u和点v的路径上的权值
(1)若u和v在同一条重链上直接用数据结构修改pos[u]至pos[v]间的值。
(2)若u和v不在同一条重链上一边进行修改,一边将u和v往同一条重链上靠,然后就变成了情况(1)。
查询操作
查询操作的分析过程同修改操作
题目不同,选用不同的数据结构来维护值,通常有线段树和splay
代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstdio> 6 #define N 30005 7 #define inf 0x7fffffff 8 int pre[N*2],now[N],v[N*2],val[N]; 9 int sum[N*4],mx[N*4]; 10 int deep[N],size[N]; 11 int pl[N],belong[N]; 12 int bin[20],ft[N][20]; 13 bool vis[N]; 14 int sz,tot,n,m,x,y; 15 using namespace std; 16 int read() 17 { 18 int x=0; char ch; bool bo=0; 19 while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') bo=1; 20 while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9'); 21 if (bo) return -x; return x; 22 } 23 void ins(int a,int b) 24 { 25 ++tot; pre[tot]=now[a]; now[a]=tot; v[tot]=b; 26 } 27 void dfs1(int u) 28 { 29 size[u]=vis[u]=1; 30 for (int i=1; i<=17; i++) 31 if (deep[u]>=bin[i]) 32 ft[u][i]=ft[ft[u][i-1]][i-1]; 33 for (int p=now[u]; p; p=pre[p]) 34 { 35 int son=v[p]; 36 if (vis[son]) continue; 37 deep[son]=deep[u]+1; 38 ft[son][0]=u; 39 dfs1(son); 40 size[u]+=size[son]; 41 } 42 } 43 void dfs2(int u,int chain) 44 { 45 pl[u]=++sz; belong[u]=chain; 46 int k=0; 47 for (int p=now[u]; p; p=pre[p]) 48 { 49 int son=v[p]; 50 if (deep[son]<deep[u]) continue; 51 if (size[son]>size[k]) k=son; 52 } 53 if (!k) return ; 54 dfs2(k,chain); 55 for (int p=now[u]; p; p=pre[p]) 56 { 57 int son=v[p]; 58 if (deep[son]<deep[u]) continue; 59 if (son!=k) dfs2(son,son); 60 } 61 } 62 int lca(int x,int y) 63 { 64 if (deep[x]<deep[y]) swap(x,y); 65 int t=deep[x]-deep[y]; 66 for (int i=0; i<=17; i++) 67 if (t&bin[i]) x=ft[x][i]; 68 for (int i=17; i>=0; i--) 69 if (ft[x][i]!=ft[y][i]) 70 { 71 x=ft[x][i]; y=ft[y][i]; 72 } 73 if (x==y) return x; else return ft[x][0]; 74 75 } 76 void pushup(int k) 77 { 78 sum[k]=sum[k*2]+sum[k*2+1]; 79 mx[k]=max(mx[k*2+1],mx[k*2]); 80 } 81 void change(int k,int l, int r, int a,int c) 82 { 83 if (l==r) 84 { 85 sum[k]=mx[k]=val[l]=c; return; 86 } 87 int mid=(l+r)>>1; 88 if (a<=mid) change(k*2,l,mid,a,c); 89 else change(k*2+1,mid+1,r,a,c); 90 pushup(k); 91 } 92 int ask(int k,int l,int r,int a,int b) 93 { 94 if (l==a&&r==b) return sum[k]; 95 int mid=(l+r)>>1; 96 if (mid>=b) return ask(k*2,l,mid,a,b); 97 else if (mid<a) return ask(k*2+1,mid+1,r,a,b); 98 else 99 { 100 return (ask(k*2,l,mid,a,mid)+ask(k*2+1,mid+1,r,mid+1,b)); 101 } 102 } 103 int askmax(int k,int l,int r,int a,int b) 104 { 105 if (l==a && r==b) return mx[k]; 106 int kk=(l==a&&r==b); 107 int mid=(l+r)>>1; 108 if (mid>=b) return askmax(k*2,l,mid,a,b); 109 else if (mid<a) return askmax(k*2+1,mid+1,r,a,b); 110 else 111 { 112 return max(askmax(k*2,l,mid,a,mid),askmax(k*2+1,mid+1,r,mid+1,b)); 113 } 114 } 115 int solvesum(int x,int y) 116 { 117 int sum=0; 118 while (belong[x]!=belong[y]) 119 { 120 sum+=ask(1,1,n,pl[belong[x]],pl[x]); 121 x=ft[belong[x]][0]; 122 } 123 if (pl[y]>pl[x]) swap(x,y); 124 sum+=ask(1,1,n,pl[y],pl[x]); 125 return sum; 126 } 127 int solvemax(int x,int y) 128 { 129 int summax=-inf; 130 while (belong[x]!=belong[y]) 131 { 132 summax=max(summax,askmax(1,1,n,pl[belong[x]],pl[x])); 133 x=ft[belong[x]][0]; 134 } 135 if (pl[y]>pl[x]) swap(x,y); 136 summax=max(summax,askmax(1,1,n,pl[y],pl[x])); 137 return summax; 138 } 139 void getmax() 140 { 141 int t=lca(x,y); 142 printf("%d ",max(solvemax(x,t),solvemax(y,t))); 143 } 144 void getchange() 145 { 146 change(1,1,n,pl[x],y); 147 } 148 void getsum() 149 { 150 int t=lca(x,y); 151 printf("%d ",solvesum(x,t)+solvesum(y,t)-val[pl[t]]); 152 } 153 void init() 154 { 155 bin[0]=1; 156 for (int i=1; i<=17; i++) bin[i]=bin[i-1]<<1; 157 n=read(); 158 for (int i=1; i<n; i++) 159 { 160 int a=read(),b=read(); 161 ins(a,b); ins(b,a); 162 } 163 dfs1(1); 164 dfs2(1,1); 165 for (int i=1; i<=n; i++) 166 { 167 change(1,1,n,pl[i],read()); 168 } 169 } 170 void solve() 171 { 172 int m=read(); 173 char ch[10]; 174 for (int i=1; i<=m; i++) 175 { 176 scanf("%s",ch); 177 x=read(); y=read(); 178 if (ch[1]=='M') getmax(); 179 if (ch[1]=='H') getchange(); 180 if (ch[1]=='S') getsum(); 181 } 182 } 183 int main() 184 { 185 init(); 186 solve(); 187 }
注:oyzx、wyf说可以不用lca来写,可我并不知道。。。。。。。(他们代码 110行 1700ms 我的 190行 3000ms)太渣了(但是这是我第一道学算法没看模版A的题,开心!!!)