HDU 3966 Aragorn's Story 树链剖分+线段树

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966

题意:给出一棵树,规定有三种操作:I操作,C1到C2路径上点的权值增加K

                 D操作,C1到C2路径上点的权值减少K

                 Q操作,查询C点的权值

思路:第一次练的树链剖分,套模板用线段树维护即可。

代码:

  1 #include <iostream>
  2 #include <string.h>
  3 #include <algorithm>
  4 #include <stdio.h>
  5 #include <vector>
  6 
  7 using namespace std;
  8 //typedef long long ll;
  9 const int MAX=50009;
 10 
 11 int n,m,p,edge,x1,y1,z1,tim;
 12 
 13 struct tr
 14 {
 15     int l,r;
 16     int sum;
 17     int lazy;
 18 }tree[4*MAX];
 19 
 20 int a[MAX];
 21 int to[2*MAX],next1[2*MAX],head[MAX];
 22 
 23 //树链剖分模板
 24 //dfs1
 25 int dep[MAX];//节点的深度
 26 int fa[MAX];//节点的父亲节点
 27 int siz[MAX];//节点的儿子个数(子节点个数)
 28 int son[MAX];//节点的重儿子
 29 //dfs2
 30 int top[MAX];//这条链的顶端节点
 31 int tid[MAX];//按照链顺序的新编号
 32 int rank1[MAX];//新编号对应的原编号
 33 
 34 void addedge(int u,int v)
 35 {
 36     to[edge]=v,next1[edge]=head[u],head[u]=edge++;
 37     to[edge]=u,next1[edge]=head[v],head[v]=edge++;
 38 }
 39 
 40 
 41 void dfs1(int u,int father,int d)//分出重儿子
 42 {
 43     dep[u]=d;
 44     fa[u]=father;
 45     siz[u]=1;
 46     for(int i=head[u];~i;i=next1[i])
 47     {
 48         int v=to[i];
 49         if(v!=father)
 50         {
 51             dfs1(v,u,d+1);
 52             siz[u]+=siz[v];
 53             if(son[u]==-1||siz[v]>siz[son[u]])
 54             {
 55                 son[u]=v;
 56             }
 57         }
 58     }
 59 }
 60 
 61 void dfs2(int u,int tp)//连点成链
 62 {
 63     top[u]=tp;
 64     tid[u]=++tim;
 65     rank1[tid[u]]=u;
 66     if(son[u]==-1) return;
 67     dfs2(son[u],tp);
 68     for(int i=head[u];~i;i=next1[i])
 69     {
 70         int v=to[i];
 71         if(v!=son[u]&&v!=fa[u])
 72         {
 73             dfs2(v,v);
 74         }
 75     }
 76 }
 77 
 78 //线段树
 79 void pushup(int x)
 80 {
 81     tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;
 82     //tree[x].sum=max(tree[x*2].sum,tree[x*2+1].sum);
 83     return;
 84 }
 85 
 86 void pushdown(int x)
 87 {
 88     int nval=tree[x].lazy;
 89     if(nval)
 90     {
 91         tree[x*2].sum+=(tree[x*2].r-tree[x*2].l+1)*nval;
 92         tree[x*2+1].sum+=(tree[x*2+1].r-tree[x*2+1].l+1)*nval;
 93         tree[x*2].lazy+=nval;
 94         tree[x*2+1].lazy+=nval;
 95         tree[x].lazy=0;
 96     }
 97     return;
 98 }
 99 
100 void build(int l,int r,int x)
101 {
102     tree[x].l=l;
103     tree[x].r=r;
104     tree[x].sum=tree[x].lazy=0;
105     if(l==r)
106     {
107         tree[x].sum=a[rank1[l]];
108         return;
109     }
110     int mid=(l+r)/2;
111     build(l,mid,x*2);
112     build(mid+1,r,x*2+1);
113     pushup(x);
114     return;
115 }
116 
117 int query(int mb,int x)
118 {
119     int nl=tree[x].l,nr=tree[x].r;
120     if(nl==nr)
121     {
122         return tree[x].sum;
123     }
124     int mid=(nl+nr)/2;
125     int ans=0;
126     pushdown(x);
127     if (mb>mid)ans=query(mb,x*2+1);
128     else ans=query(mb,x*2);
129     pushup(x);
130     return ans;
131 }
132 
133 void update(int l,int r,int val,int x)
134 {
135     int nl=tree[x].l,nr=tree[x].r;
136     if(l<=nl&&r>=nr)
137     {
138         tree[x].sum+=(nr-nl+1)*val;
139         tree[x].lazy+=val;
140         return;
141     }
142     pushdown(x);
143     int mid=(nl+nr)/2;
144     if(l<=mid)update(l,r,val,x*2);
145     if(r>mid)update(l,r,val,x*2+1);
146     pushup(x);
147     return;
148 }
149 
150 void change(int x,int y,int val)
151 {
152     while(top[x]!=top[y])
153     {
154         if(dep[top[x]]<dep[top[y]])swap(x,y);
155         update(tid[top[x]],tid[x],val,1);
156         x=fa[top[x]];
157     }
158     if(dep[x]>dep[y])swap(x,y);
159     update(tid[x],tid[y],val,1);
160     return;
161 }
162 
163 int main()
164 {
165     #ifndef ONLINE_JUDGE
166     freopen("in.txt","r",stdin);
167     #endif
168     char ch[5];
169     while(~scanf("%d%d%d",&n,&m,&p))
170     {
171         memset(head,-1,sizeof(head));
172         memset(son,-1,sizeof(son));
173         tim=0;
174         edge=0;
175         for(int i=1;i<=n;i++)
176         {
177             scanf("%d",&a[i]);
178         }
179         for(int i=1;i<=m;i++)
180         {
181             scanf("%d%d",&x1,&y1);
182             addedge(x1,y1);
183 
184         }
185         dfs1(1,0,0);
186         dfs2(1,1);
187         build(1,n,1);
188         while(p--)
189         {
190             scanf("%s",ch);
191             if(ch[0]=='Q')
192             {
193                 scanf("%d",&x1);
194                 printf("%d\n",query(tid[x1],1));
195             }
196             else
197             {
198                 scanf("%d%d%d",&x1,&y1,&z1);
199                 if(ch[0]=='D')z1=-z1;
200                 change(x1,y1,z1);
201             }
202         }
203     }
204     return 0;
205 }

 

转载于:https://www.cnblogs.com/yuehuo/p/6660509.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值