题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966
题意:
给出一棵树,并给定各个点权的值,然后有3种操作:
I C1 C2 K: 把C1与C2的路径上的所有点权值加上K
D C1 C2 K:把C1与C2的路径上的所有点权值减去K
Q C:查询节点编号为C的权值
分析:
典型的树链剖分,对节点进行操作,可以用树状数组或者线段树。
树链剖分+树状数组:
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 6 using namespace std; 7 const int maxn = 51000; 8 9 struct Edge 10 { 11 int to,next; 12 }edge[maxn*2]; 13 int head[maxn],cnt,num; 14 int a[maxn],n,m,p,c[maxn]; 15 int size[maxn],top[maxn],id[maxn],fa[maxn],son[maxn],dep[maxn]; 16 17 void init() 18 { 19 memset(head,-1,sizeof(head)); 20 memset(son,-1,sizeof(son)); 21 memset(c,0,sizeof(c)); 22 cnt=0; 23 num=0; 24 } 25 void addedge(int u,int v) 26 { 27 edge[cnt].to = v; 28 edge[cnt].next = head[u]; 29 head[u] = cnt++; 30 } 31 32 void dfs_1(int u,int f,int d) 33 { 34 dep[u]=d; 35 size[u]=1; 36 fa[u]=f; 37 for(int i=head[u];i!=-1;i=edge[i].next) 38 { 39 int v=edge[i].to; 40 if(v==f) 41 continue; 42 dfs_1(v,u,d+1); 43 size[u]+=size[v]; 44 if(son[u]==-1||size[son[u]]<size[v]) 45 son[u]=v; 46 } 47 } 48 49 void dfs_2(int u,int tp) 50 { 51 top[u] = tp; 52 id[u] = ++num; 53 if(son[u]!=-1) 54 dfs_2(son[u],tp); 55 for(int i=head[u];i!=-1;i=edge[i].next) 56 { 57 int v=edge[i].to; 58 if(v==fa[u]||v==son[u]) 59 continue; 60 dfs_2(v,v); 61 } 62 } 63 64 int lowbit(int x) 65 { 66 return x&-x; 67 } 68 69 int sum(int x) 70 { 71 int res=0; 72 while(x>0) 73 { 74 res+=c[x]; 75 x-=lowbit(x); 76 } 77 return res; 78 } 79 80 void add(int x,int d) 81 { 82 while(x<=n) 83 { 84 c[x]+=d; 85 x+=lowbit(x); 86 } 87 } 88 89 void change(int u,int v,int val) 90 { 91 int tp1=top[u],tp2=top[v]; 92 while(tp1!=tp2) 93 { 94 if(dep[tp1]<dep[tp2]) 95 { 96 swap(tp1,tp2); 97 swap(u,v); 98 } 99 add(id[tp1],val); 100 add(id[u]+1,-val); 101 u=fa[tp1]; 102 tp1=top[u]; 103 } 104 if(dep[u]>dep[v]) 105 swap(u,v); 106 add(id[u],val); 107 add(id[v]+1,-val); 108 } 109 110 int main() 111 { 112 while(~scanf("%d%d%d",&n,&m,&p)) 113 { 114 init(); 115 for(int i=1;i<=n;i++) 116 scanf("%d",&a[i]); 117 for(int i=1;i<=m;i++) 118 { 119 int u,v; 120 scanf("%d%d",&u,&v); 121 addedge(u,v); 122 addedge(v,u); 123 } 124 dfs_1(1,0,1); 125 dfs_2(1,1); 126 for(int i=1;i<=n;i++) 127 { 128 add(id[i],a[i]); 129 add(id[i]+1,-a[i]); 130 } 131 char s[5]; 132 int c1,c2,k,c; 133 for(int i=0;i<p;i++) 134 { 135 scanf("%s",s); 136 if(s[0]=='I') 137 { 138 scanf("%d%d%d",&c1,&c2,&k); 139 change(c1,c2,k); 140 } 141 if(s[0]=='D') 142 { 143 scanf("%d%d%d",&c1,&c2,&k); 144 change(c1,c2,-k); 145 } 146 if(s[0]=='Q') 147 { 148 scanf("%d",&c); 149 cout<<sum(id[c])<<endl; 150 } 151 } 152 } 153 return 0; 154 }
树链剖分+线段树:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 const int maxn = 51000; 7 int n,m,p; 8 int val[maxn],a[maxn]; 9 struct Edge 10 { 11 int to,next; 12 }edge[maxn*2]; 13 int head[maxn],add[maxn*4]; 14 int dep[maxn],fa[maxn],size[maxn],son[maxn],top[maxn],id[maxn]; 15 int cnt,num; 16 void init() 17 { 18 memset(head,-1,sizeof(head)); 19 memset(son,-1,sizeof(son)); 20 memset(add,0,sizeof(add)); 21 cnt=0; 22 num=0; 23 } 24 25 void addedge(int u,int v) 26 { 27 edge[cnt].to=v; 28 edge[cnt].next=head[u]; 29 head[u]=cnt++; 30 } 31 32 void dfs_1(int u,int f,int d) 33 { 34 dep[u]=d; 35 size[u]=1; 36 fa[u]=f; 37 for(int i=head[u];i!=-1;i=edge[i].next) 38 { 39 int v=edge[i].to; 40 if(v==f) 41 continue; 42 dfs_1(v,u,d+1); 43 size[u]+=size[v]; 44 if(son[u]==-1||size[son[u]]<size[v]) 45 son[u]=v; 46 } 47 } 48 49 void dfs_2(int u,int tp) 50 { 51 top[u] = tp; 52 id[u] = ++num; 53 if(son[u]!=-1) 54 dfs_2(son[u],tp); 55 for(int i=head[u];i!=-1;i=edge[i].next) 56 { 57 int v = edge[i].to; 58 if(v == fa[u] ||v == son[u]) 59 continue; 60 dfs_2(v,v); 61 } 62 } 63 64 struct Tree 65 { 66 int left,right; 67 int sum; 68 }tree[maxn*4]; 69 70 void pushup(int i) 71 { 72 tree[i].sum = tree[i*2].sum + tree[i*2+1].sum; 73 } 74 75 void build(int i,int begin,int end) 76 { 77 tree[i].left=begin; 78 tree[i].right=end; 79 if(begin==end) 80 { 81 tree[i].sum=val[begin]; 82 return; 83 } 84 int mid=(begin+end)/2; 85 build(i*2,begin,mid); 86 build(i*2+1,mid+1,end); 87 pushup(i); 88 } 89 90 void pushdown(int i) 91 { 92 if(add[i]) 93 { 94 add[i*2] += add[i]; 95 add[i*2+1] += add[i]; 96 int mid=(tree[i].left+tree[i].right)/2; 97 tree[i*2].sum += add[i]*(mid-tree[i].left+1); 98 tree[i*2+1].sum += add[i]*(tree[i].right-mid); 99 add[i]=0; 100 } 101 } 102 103 void update(int i,int begin,int end,int value) 104 { 105 if(tree[i].left>=begin&&tree[i].right<=end) 106 { 107 add[i]+=value; 108 tree[i].sum+=value*(tree[i].right-tree[i].left+1); 109 return; 110 } 111 pushdown(i); 112 int mid=(tree[i].left+tree[i].right)/2; 113 if(mid>=begin) 114 update(i*2,begin,end,value); 115 if(mid<end) 116 update(i*2+1,begin,end,value); 117 pushup(i); 118 } 119 120 void change(int u,int v,int value) 121 { 122 int tp1=top[u],tp2=top[v]; 123 while(tp1!=tp2) 124 { 125 if(dep[tp1]<dep[tp2]) 126 { 127 swap(tp1,tp2); 128 swap(u,v); 129 } 130 update(1,id[tp1],id[u],value); 131 u = fa[tp1]; 132 tp1 = top[u]; 133 } 134 if(dep[u]>dep[v]) 135 swap(u,v); 136 update(1,id[u],id[v],value); 137 } 138 139 long long query(int i,int begin,int end) 140 { 141 if(tree[i].left>=begin&&tree[i].right<=end) 142 return tree[i].sum; 143 pushdown(i); 144 int mid=(tree[i].left+tree[i].right)/2; 145 long long ans=0; 146 if(mid>=begin) 147 ans+=query(i*2,begin,end); 148 if(mid<end) 149 ans+=query(i*2+1,begin,end); 150 return ans; 151 } 152 153 int main() 154 { 155 while(~scanf("%d%d%d",&n,&m,&p)) 156 { 157 init(); 158 for(int i=1;i<=n;i++) 159 scanf("%d",&a[i]); 160 for(int i=1;i<=m;i++) 161 { 162 int u,v; 163 scanf("%d%d",&u,&v); 164 addedge(u,v); 165 addedge(v,u); 166 } 167 dfs_1(1,0,1); 168 dfs_2(1,1); 169 170 for(int i=1;i<=n;i++) 171 val[id[i]]=a[i]; 172 build(1,1,n); 173 char s[5]; 174 int c1,c2,k,c; 175 for(int i=0;i<p;i++) 176 { 177 scanf("%s",s); 178 if(s[0]=='I') 179 { 180 scanf("%d%d%d",&c1,&c2,&k); 181 change(c1,c2,k); 182 } 183 if(s[0]=='D') 184 { 185 scanf("%d%d%d",&c1,&c2,&k); 186 change(c1,c2,-k); 187 } 188 if(s[0]=='Q') 189 { 190 scanf("%d",&c); 191 cout<<query(1,id[c],id[c])<<endl; 192 } 193 } 194 } 195 return 0; 196 }