HDU 3966 dfs序+LCA+树状数组

题目意思很明白:

给你一棵有n个节点的树,对树有下列操作:

I c1 c2 k 意思是把从c1节点到c2节点路径上的点权值加上k

D c1 c2 k 意思是把从c1节点到c2节点路径上的点权值减去k

Q a 查询节点a的权值

数据大小 节点个数 n[1,50000], 操作次数 op[0,30000];

不会树链剖分 故只有想其他的方法。

这道题有点类似今年上海网络赛的1003 ,不过那题我没做;

算法思路:

以节点1 为根,求出节点i 的 dfs序列 tim[i][2];

其中tim[i][0]存的是进入节点i的时间 ,tim[i][1]存的是离开节点i的时间

看操作: I a b k, 节点a到b的路径上所有点+k;最朴素的算法首先找到他们的最近公共祖先(LCA)(我用RMQ)写的;然后在路径上的每一个节点都+k;

假设树根是1

从a到树根的每一个节点x都满足tim[x][0]<=tim[a][0]<=tim[x][1];如此 如果引入一个数列nt,如果nt(tim[a][0])+=k,那么 nt数列从tim[x][0]到tim[x][1]项的和就加了k,这就相当于把从a到根节点的每一个节点的权值加上了k;

如果节点x不在a到根的路径上呢?那么只有可能是tim[x][0]>tim[a][0] or tim[x][1]<tim[a][0]  故上面的这种做法对其他的点没有影响

根据这种思路 ,那解法就相对简单了:

加上差分数列的思想

a b的LCA是t,把 a b节点都加上k,然后把t的父节点-2;当然 t节点是加了两遍的 所以需要减去一遍 也就是把t节点-1,父节点当然也要+1了

 

如果有了dfs序,就可以很清晰的看出来 如果一个节点x在这条路径上 那么tim[x][0]<=one of (tim[a][0],tim[b][0])<=tim[x][1];

附上代码渣渣:

  1 // hdu 3966

  2 #include<iostream>

  3 #include<stdio.h>

  4 #include<string.h>

  5 #include <string>

  6 #include <cmath>

  7 #include <algorithm>

  8 #include <map>

  9 #include <set>

 10 #include <queue>

 11 #include <stack>

 12 #include<stdlib.h>

 13 #include <vector>

 14 using namespace std;

 15 

 16 #define ll __int64

 17 #define CL(a,b) memset(a,b,sizeof(a))

 18 #define MAX_NODE 50010

 19 

 20 int n,m,q;

 21 

 22 int log_2(int x)

 23 {

 24     return (int)(log((double)x)/log(2.0));

 25 }

 26 

 27 int tim[MAX_NODE][2],ti;

 28 int rmq[MAX_NODE*2][30],cq,fv[MAX_NODE];

 29 int pre[MAX_NODE];

 30 int value[50010];

 31 

 32 typedef struct myedge

 33 {

 34     int v,next;

 35 }E;

 36 

 37 E edge[100010];

 38 int head[50010],ce;

 39 

 40 void inithead()

 41 {

 42     CL(head,-1);

 43     ce=0;

 44 }

 45 void addedge(int s,int e)

 46 {

 47     edge[ce].v=e;edge[ce].next=head[s];head[s]=ce++;

 48     edge[ce].v=s;edge[ce].next=head[e];head[e]=ce++;

 49 }

 50 

 51 void initrmq()

 52 {

 53     int i,j;

 54     for(j=1;(1<<j)<=cq;j++)

 55     {

 56         for(i=1;i+(1<<j)-1<=cq;i++)

 57         {

 58             rmq[i][j]=min(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]);

 59         }

 60     }

 61 }

 62 int quermq(int s,int e)

 63 {

 64     int i=log_2(e-s+1);

 65     return min(rmq[s][i],rmq[e-(1<<i)+1][i]);

 66 }

 67 

 68 ll nt[50010];

 69 

 70 int lowbit(int i)

 71 {

 72     return i&(-i);

 73 }

 74 

 75 void modify(int i,ll v)

 76 {

 77     if(i==0)return ;

 78     for(i;i<=n;i+=lowbit(i))

 79     {

 80         nt[i]+=v;

 81     }

 82 }

 83 

 84 ll sum(int i)

 85 {

 86     ll rem=0;

 87     for(i;i>0;i-=lowbit(i))

 88         rem+=nt[i];

 89     return rem;

 90 }

 91 

 92 int dfs(int i,int pr)

 93 {

 94     ti++;

 95     tim[i][0]=ti;

 96 //    cout<<i<<" tim "<<ti<<endl;

 97     rmq[++cq][0]=tim[i][0];

 98     fv[i]=cq;

 99     pre[ti]=pr;

100     int p=head[i];

101     while(p!=-1)

102     {

103         int v=edge[p].v;

104         if(tim[v][0]==0)

105         {

106             dfs(v,tim[i][0]);

107             rmq[++cq][0]=tim[i][0];

108         }

109         p=edge[p].next;

110     }

111     tim[i][1]=ti;

112     return 0;

113 }

114 

115 void inc(int s,int e,int k)

116 {

117     int rs=fv[s];

118     int re=fv[e];

119     int rt=quermq(min(rs,re),max(rs,re));

120     re=tim[e][0];

121     rs=tim[s][0];

122    // cout<<rs<<' '<<re<<' '<<rt<<' '<<pre[rt]<<endl;

123     if(s==e)

124     {

125         value[s]+=k;

126         return ;

127     }

128     modify(rs,k);

129     modify(re,k);

130     modify(rt,-k);

131     modify(pre[rt],-k);

132 }

133 

134 void dec(int s,int e,int k)

135 {

136     k=-k;

137     int rs=fv[s];

138     int re=fv[e];

139     int rt=quermq(min(rs,re),max(rs,re));

140     re=tim[e][0];

141     rs=tim[s][0];

142     if(s==e)

143     {

144         value[s]+=k;

145         return ;

146     }

147     modify(rs,k);

148     modify(re,k);

149     modify(rt,-k);

150     modify(pre[rt],-k);

151 }

152 

153 ll que(int k)

154 {

155     int rl=tim[k][0];

156     int rr=tim[k][1];

157  //   cout<<rl<<' '<<rr<<endl;

158     return (ll)value[k]+sum(rr)-sum(rl-1);

159 }

160 

161 char op[3];

162 

163 

164 int main()

165 {

166     while(scanf("%d %d %d",&n,&m,&q)!=EOF)

167     {

168         CL(nt,0);

169         CL(rmq,0);cq=0;

170         CL(fv,0);

171         CL(pre,0);

172         CL(tim,0);ti=0;

173         inithead();

174         int i,j,k;

175         int a,b,c;

176         for(i=1;i<=n;i++)

177         {

178             scanf("%d",value+i);

179         }

180         for(i=1;i<n;i++)

181         {

182             scanf("%d %d",&a,&b);

183             addedge(a,b);

184         }

185         dfs(1,0);

186 /*

187         for(i=1;i<=cq;i++)

188         {

189             printf("%d ",rmq[i][0]);

190         }cout<<endl;

191 */

192         initrmq();

193         for(i=0;i<q;i++)

194         {

195             scanf("%s",op);

196             if(op[0]=='I')

197             {

198                 scanf("%d %d %d",&a,&b,&c);

199                 inc(a,b,c);

200             }

201             else if(op[0]=='D')

202             {

203                 scanf("%d %d %d",&a,&b,&c);

204                 dec(a,b,c);

205             }

206             else if(op[0]=='Q')

207             {

208                 scanf("%d",&a);

209                 printf("%I64d\n",que(a));

210             }

211         }

212 

213     }

214 

215     return 0;

216 }

 

你可能感兴趣的:(树状数组)