树链剖分(BZOJ 1036)
Notes:莫名其妙WA一定是数组开小了!!!
一句话树链剖分:将一棵树“剖分”为多条链再映射到线段树上维护
时间复杂度:O(n(logn)^2)
BZOJ 1036题意:
一棵树上有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本身
1 #include <cstdio> 2 inline int max(int a,int b) 3 { 4 return a>b?a:b; 5 } 6 inline void swap(int &a,int &b) 7 { 8 register int tmp=a; 9 a=b;b=tmp; 10 } 11 inline void read(int &k) 12 { 13 register int f=1,c=getchar();k=0; 14 while (c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); 15 while (c>='0'&&c<='9')k=k*10+c-'0',c=getchar(); 16 k*=f; 17 } 18 const int maxn=301000*2,inf=1<<30; 19 struct node{ 20 int l,r,mx,sum; 21 }tree[maxn]; 22 char s[233]; 23 bool vis[maxn]; 24 int n,a,b,q,tot,u,v,tmp,cnt; 25 int last[maxn],nxt[maxn],to[maxn],depth[maxn],top[maxn],siz[maxn],pos[maxn],fa[maxn]; 26 void build(int l,int r,int cur) 27 { 28 tree[cur].l=l;tree[cur].r=r; 29 if (l==r)return; 30 register int mid=(l+r)>>1; 31 build(l,mid,cur<<1); 32 build(mid+1,r,cur<<1|1); 33 } 34 void change(int x,int t,int cur) 35 { 36 if (tree[cur].l==tree[cur].r){tree[cur].mx=tree[cur].sum=t;return;} 37 register int mid=(tree[cur].l+tree[cur].r)>>1; 38 if (x<=mid)change(x,t,cur<<1);else change(x,t,cur<<1|1); 39 tree[cur].sum=tree[cur<<1].sum+tree[cur<<1|1].sum; 40 tree[cur].mx=max(tree[cur<<1].mx,tree[cur<<1|1].mx); 41 } 42 int querymx(int l,int r,int cur) 43 { 44 if (l<=tree[cur].l&&tree[cur].r<=r)return tree[cur].mx; 45 register int mid=(tree[cur].l+tree[cur].r)>>1,ans=-inf; 46 if (l<=mid)ans=querymx(l,r,cur<<1); 47 if (r>mid)ans=max(ans,querymx(l,r,cur<<1|1)); 48 return ans; 49 } 50 int querysum(int l,int r,int cur) 51 { 52 if (l<=tree[cur].l&&tree[cur].r<=r)return tree[cur].sum; 53 register int ans=0,mid=(tree[cur].l+tree[cur].r)>>1; 54 if (l<=mid)ans=querysum(l,r,cur<<1); 55 if (r>mid)ans+=querysum(l,r,cur<<1|1); 56 return ans; 57 } 58 void dfs(int now) 59 { 60 vis[now]=1;siz[now]=1; 61 for (register int i=last[now];i;i=nxt[i]) 62 { 63 if (vis[to[i]])continue; 64 fa[to[i]]=now; 65 depth[to[i]]=depth[now]+1; 66 dfs(to[i]); 67 siz[now]+=siz[to[i]]; 68 } 69 } 70 void _dfs(int now,int t) 71 { 72 register int p=0; 73 pos[now]=++cnt; 74 top[now]=t; 75 for (register int i=last[now];i;i=nxt[i]) 76 if (depth[to[i]]>depth[now]&&siz[to[i]]>siz[p])p=to[i]; 77 if (!p)return; 78 _dfs(p,t); 79 for (register int i=last[now];i;i=nxt[i]) 80 if (depth[to[i]]>depth[now]&&to[i]!=p)_dfs(to[i],to[i]); 81 } 82 inline int solvemx(int a,int b) 83 { 84 register int ans=-inf; 85 while(top[a]!=top[b]) 86 { 87 if (depth[top[a]]<depth[top[b]])swap(a,b); 88 ans=max(ans,querymx(pos[top[a]],pos[a],1)); 89 a=fa[top[a]]; 90 } 91 if (pos[a]>pos[b])swap(a,b); 92 return max(querymx(pos[a],pos[b],1),ans); 93 } 94 inline int solvesum(int a,int b) 95 { 96 register int ans=0; 97 while(top[a]!=top[b]) 98 { 99 if (depth[top[a]]<depth[top[b]])swap(a,b); 100 ans+=querysum(pos[top[a]],pos[a],1); 101 a=fa[top[a]]; 102 } 103 if (pos[a]>pos[b])swap(a,b); 104 return ans+querysum(pos[a],pos[b],1); 105 } 106 inline void work() 107 { 108 read(n); 109 for (register int i=1;i<n;i++) 110 { 111 read(u);read(v); 112 nxt[++tot]=last[u]; 113 last[u]=tot; 114 to[tot]=v; 115 nxt[++tot]=last[v]; 116 last[v]=tot; 117 to[tot]=u; 118 } 119 build(1,n,1); 120 depth[1]=1; 121 dfs(1); 122 _dfs(1,1); 123 for (register int i=1;i<=n;i++) 124 { 125 read(tmp); 126 change(pos[i],tmp,1); 127 } 128 read(q); 129 for (register int i=1;i<=q;i++) 130 { 131 scanf("%s",s);read(a);read(b); 132 if (s[3]=='X')//QMAX 133 printf("%d\n",solvemx(a,b)); 134 else if (s[0]=='C')//CHANGE 135 change(pos[a],b,1); 136 else //QSUM 137 printf("%d\n",solvesum(a,b)); 138 } 139 } 140 int main() 141 { 142 work(); 143 return 0; 144 }