题目:https://www.luogu.org/problemnew/show/2590
题目描述
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身
输入输出格式
输入格式:
输入文件的第一行为一个整数n,表示节点的个数。
接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
接下来一行n个整数,第i个整数wi表示节点i的权值。
接下来1行,为一个整数q,表示操作的总数。
接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
输出格式:
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
输入输出样例
说明
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
解析
这个。。。没有啥可解析的吧。。。。。。
树剖版题。
我终于写对了一个树剖啦。。。。。。
(我还是太菜了)
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<vector> 7 using namespace std; 8 const int N=30500; 9 const int M=70500; 10 const int inf=233333333; 11 12 vector<int> edge[N]; 13 14 int n,m,ra,rb; 15 int val[N]; 16 int fa[N],tot[N],depth[N]; 17 int top[N],num[N],numx[N],t; 18 19 struct node{ 20 int maxv,sum; 21 }; 22 node tree[M]; 23 24 void addedge(int x,int y){ 25 edge[x].push_back(y); 26 edge[y].push_back(x); 27 } 28 29 void dfsa(int x){ 30 depth[x]=depth[fa[x]]+1; 31 tot[x]=1; 32 for (int i=0;i<edge[x].size();++i){ 33 int nxt=edge[x][i]; 34 if (nxt!=fa[x]){ 35 fa[nxt]=x; 36 dfsa(nxt); 37 tot[x]+=tot[nxt]; 38 } 39 } 40 } 41 42 void dfsb(int x){ 43 ++t; 44 num[x]=t; 45 numx[t]=x; 46 if (!top[x]) top[x]=x; 47 int big=0; 48 for (int i=0;i<edge[x].size();++i){ 49 int nxt=edge[x][i]; 50 if (nxt!=fa[x]&&tot[nxt]>tot[big]) 51 big=nxt; 52 } 53 if (big){ 54 top[big]=top[x]; 55 dfsb(big); 56 } 57 for (int i=0;i<edge[x].size();++i){ 58 int nxt=edge[x][i]; 59 if (nxt!=fa[x]&&nxt!=big) 60 dfsb(nxt); 61 } 62 } 63 64 void maketree(int o,int l,int r){ 65 if (l==r){ 66 tree[o].maxv=val[numx[l]]; 67 tree[o].sum=val[numx[l]]; 68 return; 69 } 70 int ls=o<<1; 71 int rs=ls|1; 72 int mid=(l+r)>>1; 73 maketree(ls,l,mid); 74 maketree(rs,mid+1,r); 75 tree[o].sum=tree[ls].sum+tree[rs].sum; 76 tree[o].maxv=max(tree[ls].maxv,tree[rs].maxv); 77 } 78 79 void change(int o,int l,int r,int a,int v){ 80 if (l==r){ 81 tree[o].maxv=tree[o].sum=v; 82 return; 83 } 84 int mid=(l+r)>>1; 85 int ls=o<<1; 86 int rs=ls|1; 87 if (a<=mid) change(ls,l,mid,a,v); 88 else change(rs,mid+1,r,a,v); 89 tree[o].maxv=max(tree[ls].maxv,tree[rs].maxv); 90 tree[o].sum=tree[ls].sum+tree[rs].sum; 91 } 92 93 int getsum(int o,int l,int r,int ql,int qr){ 94 if (ql<=l&&qr>=r) return tree[o].sum; 95 int mid=(l+r)>>1; 96 int ls=o<<1; 97 int rs=ls|1; 98 int ans=0; 99 if (ql<=mid) ans+=getsum(ls,l,mid,ql,qr); 100 if (qr>mid) ans+=getsum(rs,mid+1,r,ql,qr); 101 return ans; 102 } 103 int getmax(int o,int l,int r,int ql,int qr){ 104 if (ql<=l&&qr>=r) return tree[o].maxv; 105 int mid=(l+r)>>1; 106 int ls=o<<1; 107 int rs=ls|1; 108 int ans=-inf; 109 if (ql<=mid) ans=max(ans,getmax(ls,l,mid,ql,qr)); 110 if (qr>mid) ans=max(ans,getmax(rs,mid+1,r,ql,qr)); 111 return ans; 112 } 113 114 int findmax(int a,int b){ 115 int res=-inf; 116 while (top[a]!=top[b]){ 117 if (depth[top[a]]<depth[top[b]]){ 118 swap(a,b); 119 } 120 res=max(res,getmax(1,1,n,num[top[a]],num[a])); 121 a=fa[top[a]]; 122 } 123 if (depth[a]>depth[b]) swap(a,b); 124 res=max(res,getmax(1,1,n,num[a],num[b])); 125 return res; 126 } 127 int findsum(int a,int b){ 128 int res=0; 129 while (top[a]!=top[b]){ 130 if (depth[top[a]]<depth[top[b]]){ 131 swap(a,b); 132 } 133 res+=getsum(1,1,n,num[top[a]],num[a]); 134 a=fa[top[a]]; 135 } 136 if (depth[a]>depth[b]) swap(a,b); 137 res+=getsum(1,1,n,num[a],num[b]); 138 return res; 139 } 140 141 int main(){ 142 scanf("%d",&n); 143 for (int i=1;i<n;++i){ 144 scanf("%d%d",&ra,&rb); 145 addedge(ra,rb); 146 } 147 for (int i=1;i<=n;++i) 148 scanf("%d",&val[i]); 149 dfsa(1); 150 dfsb(1); 151 maketree(1,1,n); 152 scanf("%d",&m); 153 char re[10]; 154 while (m--){ 155 scanf("%s%d%d",re,&ra,&rb); 156 if (re[0]=='C') change(1,1,n,num[ra],rb); 157 else if (re[1]=='M') printf("%d ",findmax(ra,rb)); 158 else printf("%d ",findsum(ra,rb)); 159 } 160 return 0; 161 }