爱悠闲 > POJ 3237树链剖分

POJ 3237树链剖分

分类: 基础图论  |  作者: xianxingwuguan1 相关  |  发布日期 : 2014-05-29  |  热度 : 44°
Tree
Time Limit: 5000MS   Memory Limit: 131072K
Total Submissions: 3189   Accepted: 897

Description

You are given a tree with N nodes. The tree’s nodes are numbered 1 throughN 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

Input

The input contains multiple test cases. The first line of input contains an integert (t ≤ 20), the number of test cases. Then follow the test cases.

Each test case is preceded by an empty line. The first nonempty line of its containsN (N ≤ 10,000). The next N − 1 lines each contains three integersa, b and c, describing an edge connecting nodes a and b with weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE” ends the test case.

Output

For each “QUERY” instruction, output the result on a separate line.

Sample Input

1

3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

Sample Output

1
3


题意:给定一颗树,有三种操作:(1)改变第i条边的权值,(2)将从u到v路径上的权值取反,(3)查询从u到v路径上的最大权。

解题思路:首先轻重链剖分,然后线段树维护最大值,最小值,以及取反标记。

代码:

/* ***********************************************
Author :xianxingwuguan
Created Time :2014-1-24 13:55:10
File Name :2.cpp
************************************************ */

#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int maxn=110000;
const int inf=1000000000;
int head[maxn],tol,top[maxn],p[maxn],fp[maxn],num[maxn],fa[maxn],son[maxn],deep[maxn],pos;
struct node 
{
      int next,to;
}edge[10*maxn];
void add(int u,int v)
{
      edge[tol].next=head[u];
      edge[tol].to=v;
      head[u]=tol++;
}
void init()
{
      memset(head,-1,sizeof(head));
      tol=0;
      memset(son,-1,sizeof(son));
      pos=0;
}
void dfs(int u,int pre,int d)
{
      deep[u]=d;
      num[u]=1;
      fa[u]=pre;
      for(int i=head[u];i!=-1;i=edge[i].next)
      {
	     int v=edge[i].to;
	     if(v==pre)continue;
	     dfs(v,u,d+1);
	     num[u]+=num[v];
	     if(son[u]==-1||num[v]>num[son[u]])
		    son[u]=v;
      }
}
void getpos(int u,int sp)
{
      top[u]=sp;
      p[u]=pos++;
      fp[p[u]]=u;
      if(son[u]==-1)return;
      getpos(son[u],sp);
      for(int i=head[u];i!=-1;i=edge[i].next)
      {
	     int v=edge[i].to;
	     if(v!=fa[u]&&v!=son[u])
		    getpos(v,v);
      }
}
struct NODE 
{
      int l,r,max,min,neg;
}tree[6*maxn];
void pushup(int i)
{
      tree[i].max=max(tree[2*i].max,tree[2*i+1].max);
      tree[i].min=min(tree[2*i].min,tree[2*i+1].min);
}
void pushdown(int i)
{
      if(tree[i].l==tree[i].r)return;
      if(tree[i].neg)
      {
           tree[2*i].max=-tree[2*i].max;
	    tree[2*i].min=-tree[2*i].min;
	    swap(tree[2*i].max,tree[2*i].min);
	    tree[2*i].neg^=1;

	    tree[2*i+1].max=-tree[2*i+1].max;
	    tree[2*i+1].min=-tree[2*i+1].min;
           swap(tree[2*i+1].max,tree[2*i+1].min);
	    tree[2*i+1].neg^=1;
	    
	    tree[i].neg=0;
      }
}
void build(int l,int r,int i)
{
      tree[i].l=l;
      tree[i].r=r;
      tree[i].neg=0;
      tree[i].max=0;
      tree[i].min=0;
      if(l==r)return;
      int mid=(l+r)/2;
      build(l,mid,2*i);
      build(mid+1,r,2*i+1);
}
void update1(int i,int pos,int val)
{
      if(tree[i].l==tree[i].r)
      {
	     tree[i].max=tree[i].min=val;
	     tree[i].neg=0;
	     return;
      }
      pushdown(i);
      int mid=(tree[i].l+tree[i].r)>>1;
      if(pos<=mid)update1(2*i,pos,val);
      else update1(2*i+1,pos,val);
      pushup(i);
}
void negval(int i,int l,int r)
{
      if(tree[i].l>=l&&tree[i].r<=r)
      {
	     tree[i].max=-tree[i].max;
	     tree[i].min=-tree[i].min;
	     swap(tree[i].max,tree[i].min);
	     tree[i].neg^=1;
	     return;
      }
      pushdown(i);
      int mid=(tree[i].l+tree[i].r)>>1;
      if(l<=mid)negval(2*i,l,r);
      if(r>mid)negval(2*i+1,l,r);
      pushup(i);
}
int query(int i,int l,int r)
{
      if(tree[i].l>=l&&tree[i].r<=r)return tree[i].max;
      pushdown(i);
      int mid=(tree[i].l+tree[i].r)>>1;
      int ans=-inf;
      if(l<=mid)ans=max(ans,query(2*i,l,r));
      if(r>mid)ans=max(ans,query(2*i+1,l,r));
      pushup(i);
      return ans;
}
int findmax(int u,int v)
{
      int f1=top[u],f2=top[v];
      int tmp=-inf;
      while(f1!=f2)
      {
	     if(deep[f1]<deep[f2])
	     {
		    swap(f1,f2);
		    swap(u,v);
	     }
	     tmp=max(tmp,query(1,p[f1],p[u]));
	     u=fa[f1];
	     f1=top[u];
      }
      if(u==v)return tmp;
      if(deep[u]>deep[v])swap(u,v);
      return max(tmp,query(1,p[son[u]],p[v]));
}
void neg(int u,int v)
{
      int f1=top[u],f2=top[v];
      while(f1!=f2)
      {
	     if(deep[f1]<deep[f2])
	     {
		    swap(f1,f2);
		    swap(u,v);
	     }
	     negval(1,p[f1],p[u]);
	     u=fa[f1];
	     f1=top[u];
      }
      if(u==v)return;
      if(deep[u]>deep[v])swap(u,v);
      negval(1,p[son[u]],p[v]);
}
int e[maxn][3];
int main()
{
     // freopen("tree.in","r",stdin);
    // freopen("data.out","w",stdout);
      int T,n;
      scanf("%d",&T);
      while(T--)
      {
	     init();
	     scanf("%d",&n);
	     for(int i=0;i<n-1;i++)
	     {
		    scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
		    add(e[i][0],e[i][1]);
		    add(e[i][1],e[i][0]);
	     }
	     dfs(1,0,0);
	     getpos(1,1);
	    // cout<<pos<<endl;
	     build(0,pos-1,1);
	     for(int i=0;i<n-1;i++)
	     {
		    if(deep[e[i][0]]>deep[e[i][1]])
			   swap(e[i][0],e[i][1]);
		    update1(1,p[e[i][1]],e[i][2]);
	     }
	     char op[10];
	     int u,v;
	     while(~scanf("%s",op))
	     {
		    if(op[0]=='D')break;
		    scanf("%d%d",&u,&v);
		    if(op[0]=='Q')
			   printf("%d\n",findmax(u,v));
		    else if(op[0]=='C')
			   update1(1,p[e[u-1][1]],v);
		    else neg(u,v);
	     }
      }
      return 0;
}