poj 3237 Tree 树链剖分

题目链接:http://poj.org/problem?id=3237

You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:

CHANGE i v Change the weight of the ith edge to v
NEGATE a b Negate the weight of every edge on the path from a to b
QUERY a b Find the maximum weight of edges on the path from a to b

题意描述:一棵树有n个节点和n-1条边,每条边有一个权值。现在给出三种操作:

CHANGE I V:把第i条边的值改为v

NEGATE A B:把A到B的路径上的所有边的值取反(正为负,负改为正)

QUERY A B:询问A到B的路径上的边权值的最大值。

算法分析:树链剖分解决。把边权值移到节点上面,由于操作上有对值取反,所有我们不止要运用线段树统计区间最大值maxnum,还要统计区间最小值minnum,这样在取反操作后,maxnum=-maxnum,minnum=-minnum,再把两个值交换:swap(maxnum,minnum)即可。

说明:阅读了一些大牛的代码,感觉线段树部分还是结构体比数组方便一些,树链剖分刚开始学,代码和解题思想很多是借鉴大牛们的,只是把代码风格改成自己的了,相信只有不断学习和解题才会对树链剖分有一定理解的。

  1 #include<iostream>

  2 #include<cstdio>

  3 #include<cstring>

  4 #include<cstdlib>

  5 #include<cmath>

  6 #include<algorithm>

  7 #include<vector>

  8 #define inf 0x7fffffff

  9 using namespace std;

 10 const int maxn=100000+10;

 11 

 12 struct Edge

 13 {

 14     int to,next;

 15 }edge[maxn*2];

 16 int head[maxn],edgenum;

 17 int top[maxn];//top[v]表示v所在的重链的顶端节点

 18 int fa[maxn]; //父亲节点

 19 int dep[maxn];//深度

 20 int siz[maxn];//siz[v]表示以v为根的子树的节点数

 21 int tid[maxn];//tid[v]表示v与其父亲节点的连边在线段树中的位置

 22 int tid2[maxn];//和tid数组相反

 23 int son[maxn];//重儿子

 24 int pos;

 25 void init()

 26 {

 27     edgenum=0;

 28     memset(head,-1,sizeof(head));

 29     pos=0;

 30     memset(son,-1,sizeof(son));

 31 }

 32 void addedge(int u,int v)

 33 {

 34     edge[edgenum].to=v ;edge[edgenum].next=head[u];

 35     head[u]=edgenum++;

 36 

 37     edge[edgenum].to=u ;edge[edgenum].next=head[v];

 38     head[v]=edgenum++;

 39 }

 40 

 41 void dfs1(int u,int pre,int d) //第一遍dfs求出fa,dep,siz,son

 42 {

 43     dep[u]=d;

 44     fa[u]=pre;

 45     siz[u]=1;

 46     for (int i=head[u] ;i != -1 ;i=edge[i].next)

 47     {

 48         int v=edge[i].to;

 49         if (v != pre)

 50         {

 51             dfs1(v,u,d+1);

 52             siz[u] += siz[v];

 53             if (son[u] == -1 || siz[v]>siz[son[u]])

 54                 son[u]=v;

 55         }

 56     }

 57 }

 58 void dfs2(int u,int tp) //第二遍dfs求出top和tid

 59 {

 60     top[u]=tp;

 61     tid[u]= ++pos;

 62     tid2[pos]=u;

 63     if (son[u] == -1) return;

 64     dfs2(son[u],tp);

 65     for (int i=head[u] ;i != -1 ;i=edge[i].next)

 66     {

 67         int v=edge[i].to;

 68         if (v != son[u] && v != fa[u])

 69             dfs2(v,v);

 70     }

 71 }

 72 

 73 //线段树

 74 struct node

 75 {

 76     int l,r;

 77     int Max;

 78     int Min;

 79     int ne;

 80 }segTree[maxn*3];

 81 

 82 void build(int l,int r,int rt)

 83 {

 84     segTree[rt].l=l;

 85     segTree[rt].r=r;

 86     segTree[rt].Max=0;

 87     segTree[rt].Min=0;

 88     segTree[rt].ne=0;

 89     if (l==r) return ;

 90     int mid=(l+r)/2;

 91     build(l,mid,rt<<1);

 92     build(mid+1,r,rt<<1|1);

 93 }

 94 void PushUP(int rt)

 95 {

 96     segTree[rt].Max = max(segTree[rt<<1].Max,segTree[rt<<1|1].Max);

 97     segTree[rt].Min = min(segTree[rt<<1].Min,segTree[rt<<1|1].Min);

 98 }

 99 void PushDown(int rt)

100 {

101     if (segTree[rt].l == segTree[rt].r) return ;

102     if (segTree[rt].ne)

103     {

104         segTree[rt<<1].Max = -segTree[rt<<1].Max;

105         segTree[rt<<1].Min = -segTree[rt<<1].Min;

106         swap(segTree[rt<<1].Min,segTree[rt<<1].Max);

107         segTree[rt<<1|1].Max = -segTree[rt<<1|1].Max;

108         segTree[rt<<1|1].Min = -segTree[rt<<1|1].Min;

109         swap(segTree[rt<<1|1].Max,segTree[rt<<1|1].Min);

110         segTree[rt<<1].ne ^= 1;

111         segTree[rt<<1|1].ne ^= 1;

112         segTree[rt].ne = 0;

113     }

114 }

115 

116 void update(int k,int val,int rt) // 更新线段树的第k个值为val

117 {

118     if(segTree[rt].l == k && segTree[rt].r == k)

119     {

120         segTree[rt].Max = val;

121         segTree[rt].Min = val;

122         segTree[rt].ne = 0;

123         return;

124     }

125     PushDown(rt);

126     int mid = (segTree[rt].l + segTree[rt].r)/2;

127     if(k <= mid)update(k,val,rt<<1);

128     else update(k,val,(rt<<1)|1);

129     PushUP(rt);

130 }

131 void ne_update(int l,int r,int rt) // 更新线段树的区间[l,r]取反

132 {

133     if (segTree[rt].l == l && segTree[rt].r == r)

134     {

135         segTree[rt].Max = -segTree[rt].Max;

136         segTree[rt].Min = -segTree[rt].Min;

137         swap(segTree[rt].Max,segTree[rt].Min);

138         segTree[rt].ne ^= 1;

139         return;

140     }

141     PushDown(rt);

142     int mid = (segTree[rt].l + segTree[rt].r)/2;

143     if (r <= mid) ne_update(l,r,rt<<1);

144     else if (l > mid) ne_update(l,r,(rt<<1)|1);

145     else

146     {

147         ne_update(l,mid,rt<<1);

148         ne_update(mid+1,r,(rt<<1)|1);

149     }

150     PushUP(rt);

151 }

152 int query(int l,int r,int rt)  //查询线段树中[l,r] 的最大值

153 {

154     if (segTree[rt].l == l && segTree[rt].r == r)

155         return segTree[rt].Max;

156     PushDown(rt);

157     int mid = (segTree[rt].l+segTree[rt].r)>>1;

158     if (r <= mid) return query(l,r,rt<<1);

159     else if (l > mid) return query(l,r,(rt<<1)|1);

160     else return max(query(l,mid,rt<<1),query(mid+1,r,(rt<<1)|1));

161     PushUP(rt);

162 }

163 int findmax(int u,int v)//查询u->v边的最大值

164 {

165     int f1 = top[u], f2 = top[v];

166     int tmp = -100000000;

167     while(f1 != f2)

168     {

169         if(dep[f1] < dep[f2])

170         {

171             swap(f1,f2);

172             swap(u,v);

173         }

174         tmp = max(tmp,query(tid[f1],tid[u],1));

175         u = fa[f1]; f1 = top[u];

176     }

177     if(u == v)return tmp;

178     if(dep[u] > dep[v]) swap(u,v);

179     return max(tmp,query(tid[son[u]],tid[v],1));

180 }

181 

182 void Negate(int u,int v)

183 {

184     int f1=top[u],f2=top[v];

185     while (f1 != f2)

186     {

187         if (dep[f1]<dep[f2])

188         {

189             swap(f1,f2);

190             swap(u,v);

191         }

192         ne_update(tid[f1],tid[u],1);

193         u=fa[f1] ;f1=top[u];

194     }

195     if (u==v) return;

196     if (dep[u]>dep[v]) swap(u,v);

197     return ne_update(tid[son[u] ],tid[v],1);

198 }

199 

200 int e[maxn][3];

201 int main()

202 {

203     int T;

204     int n;

205     scanf("%d",&T);

206     while(T--)

207     {

208         init();

209         scanf("%d",&n);

210         for(int i = 0;i < n-1;i++)

211         {

212             scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);

213             addedge(e[i][0],e[i][1]);

214         }

215         dfs1(1,0,0);

216         dfs2(1,1);

217         build(1,n,1);

218         for (int i = 0;i < n-1; i++)

219         {

220             if (dep[e[i][0]]>dep[e[i][1]])

221                 swap(e[i][0],e[i][1]);

222             update(tid[e[i][1]],e[i][2],1);

223         }

224         char op[10];

225         int u,v;

226         while (scanf("%s",op) == 1)

227         {

228             if (op[0] == 'D') break;

229             scanf("%d%d",&u,&v);

230             if (op[0]=='Q')

231                 printf("%d\n",findmax(u,v));//查询u->v路径上边权的最大值

232             else if (op[0]=='C')

233                 update(tid[e[u-1][1]],v,1);//改变第u条边的值为v

234             else Negate(u,v);

235         }

236     }

237     return 0;

238 }

 

你可能感兴趣的:(tree)