poj 3237 线段树+树链剖分

来源:互联网 发布:id软件怎么用 编辑:程序博客网 时间:2024/05/16 07:22
Tree
Time Limit: 5000MS Memory Limit: 131072KTotal Submissions: 3587 Accepted: 1004

Description

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 vChange the weight of the ith edge to vNEGATE a bNegate the weight of every edge on the path from a to bQUERY a bFind 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 integer t (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 contains N (N ≤ 10,000). The next N − 1 lines each contains three integers ab 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

131 2 12 3 2QUERY 1 2CHANGE 1 3QUERY 1 2DONE

Sample Output

13

Source

POJ Monthly--2007.06.03, Lei, Tao

题意:给一棵树,三种操作。将第i条边的权值改为v,将a到b的路径上的边的权值全部取反,求a到b路径上边的权值的最大值。

思路:明显的树链剖分,加上线段树的操作。因为有取反的操作所以每个区间要记录最大值和最小值。查询两点间的路径时,用求公共祖先的方式去求。

#include<stdio.h>#include<algorithm>#include<string.h>#define N 20005#define inf 0x3fffffffusing namespace std;struct line{    int x,y,w;}ed[N];struct node{    int u,v,w,next;}bian[N*2];struct pp{    int x,y,ma,mi,p;}a[N*3];int e,id;int sz[N],dep[N],head[N],top[N],son[N],father[N],ti[N];int max(int a,int b){    return a>b?a:b;}int min(int a,int b){    return a<b?a:b;}void add(int u,int v,int w){    bian[e].u=u;    bian[e].v=v;    bian[e].w=w;    bian[e].next=head[u];    head[u]=e++;}void dfs1(int u,int fa){    int i,v;    sz[u]=1; dep[u]=dep[fa]+1; son[u]=0;  father[u]=fa;    for(i=head[u];i!=-1;i=bian[i].next)    {        v=bian[i].v;        if(v==fa) continue;        dfs1(v,u);        sz[u]+=sz[v];        if(sz[son[u]]<sz[v])            son[u]=v;    }}void dfs2(int u,int fa){    int i,v;    top[u]=fa;    ti[u]=id++;    if(son[u]!=0)        dfs2(son[u],fa);    for(i=head[u];i!=-1;i=bian[i].next)    {        v=bian[i].v;        if(v==son[u]||v==father[u])            continue;        dfs2(v,v);    }}void pushdown(int t){    int temp=t<<1;    a[t].ma=max(a[temp].ma,a[temp+1].ma);    a[t].mi=min(a[temp].mi,a[temp+1].mi);}void build(int t ,int x,int y){    a[t].x=x; a[t].y=y;  a[t].ma=a[t].mi=a[t].p=0;    if(x==y)  return;    int mid=(x+y)>>1,temp=t<<1;    build(temp,x,mid);    build(temp+1,mid+1,y);}void find(int t){    int temp=t<<1;    if(a[t].p)    {        a[temp].ma=-a[temp].ma; a[temp].mi=-a[temp].mi;        swap(a[temp].ma,a[temp].mi);        a[temp+1].ma=-a[temp+1].ma; a[temp+1].mi=-a[temp+1].mi;        swap(a[temp+1].ma,a[temp+1].mi);        a[temp].p^=1;        a[temp+1].p^=1;        a[t].p=0;    }}int query(int t,int x,int y)//查询线段树中[x,y]的最大值{    int ma;    if(a[t].x==x&&a[t].y==y)        return a[t].ma;    int mid=(a[t].x+a[t].y)>>1,temp=t<<1;    find(t);    if(y<=mid)        return query(temp,x,y);    else if(x>mid)        return query(temp+1,x,y);    else        return max(query(temp,x,mid),query(temp+1,mid+1,y));}int lca(int x,int y)//返回最大值{    int ans;    ans=-inf;    while(top[x]!=top[y])    {        if(dep[top[x]]<dep[top[y]])            swap(x,y);        ans=max(ans,query(1,ti[top[x]],ti[x]));        x=father[top[x]];    }    if(dep[x]>dep[y])        swap(x,y);    if(x!=y)        ans=max(ans,query(1,ti[x]+1,ti[y]));    return ans;}void update(int t ,int x,int w)//更新线段树的第x个值为w{    if(a[t].x==a[t].y)    {       a[t].ma=a[t].mi=w;       a[t].p=0;        return;    }    int mid=(a[t].x+a[t].y)>>1,temp=t<<1;    find(t);    if(x<=mid)        update(temp,x,w);    else        update(temp+1,x,w);    pushdown(t);}void reupdate(int t,int x,int y)//更新线段树的区间[x,y]取反{    if(a[t].x==x&&a[t].y==y)    {        a[t].ma=-a[t].ma; a[t].mi=-a[t].mi;        swap(a[t].ma,a[t].mi);        a[t].p^=1;        return ;    }    int mid=(a[t].x+a[t].y)>>1,temp=t<<1;    find(t);    if(y<=mid)        reupdate(temp,x,y);    else if(x>mid)        reupdate(temp+1,x,y);    else    {        reupdate(temp,x,mid);        reupdate(temp+1,mid+1,y);    }    pushdown(t);}void relca(int x,int y)//把x到y路径上的值都取反{    while(top[x]!=top[y])    {        if(dep[top[x]]<dep[top[y]])            swap(x,y);        reupdate(1,ti[top[x]],ti[x]);        x=father[top[x]];    }    if(dep[x]>dep[y])        swap(x,y);    if(x!=y)        reupdate(1,ti[x]+1,ti[y]);}int main(){    int t,i,x,y,v,n;    char str[100];    scanf("%d",&t);    while(t--)    {        scanf("%d",&n);        e=0;  memset(head,-1,sizeof(head));        for(i=1;i<n;i++)        {            scanf("%d%d%d",&ed[i].x,&ed[i].y,&ed[i].w);            add(ed[i].x,ed[i].y,ed[i].w);            add(ed[i].y,ed[i].x,ed[i].w);        }        dep[1]=0;  id=1;  sz[0]=0;        dfs1(1,1);        dfs2(1,1);     //for(i=1;i<=n;i++)       // printf("i=%d size=%d top=%d father=%d son=%d ti=%d dep=%d\n",i,sz[i],top[i],father[i],son[i],ti[i],dep[i]);        build(1,1,n);        for(i=1;i<n;i++)        {            if(dep[ed[i].x]<dep[ed[i].y])                swap(ed[i].x,ed[i].y);            update(1,ti[ed[i].x],ed[i].w);        }        while(scanf("%s",str),strcmp(str,"DONE")!=0)        {            if(str[0]=='Q')            {                scanf("%d%d",&x,&y);                printf("%d\n",lca(x,y));//查询x->y路径上边权的最大值            }            else if(str[0]=='N')            {                scanf("%d%d",&x,&y);                relca(x,y);            }            else if(str[0]=='C')            {                scanf("%d%d",&i,&v);//改变第i条边的值为v                update(1,ti[ed[i].x],v);            }        }    }    return 0;}


0 0