Tree - POJ 3237 树链刨分

Tree
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 6101 Accepted: 1671

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 v
NEGATE a bNegate the weight of every edge on the path from a to b
QUERY 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

1

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

Sample Output

1
3

题意:给你一棵树,边上有权值,更新操作有将一个路径上的值取反,和更改一个点的值。查询操作查询两个点之间路径的最大边值。

思路:树链刨分,就是线段树敲起来复杂了些。

AC代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node1
{
    int u,v,w;
}arr[10010];
struct node2
{
    int u,v,w,next;
}edge[20010];
struct node3
{
    int l,r,maxn,minn,lazy;
}tree[40010];
int T,t,n,m,tot,tot2,Head[10010],INF=1e9;
int siz[10010],son[10010],depth[10010],fa[10010],top[10010],p[10010];
int W[10010];
char s[10];
void dfs1(int u)
{
    int i,j,k,v;
    siz[u]=1;
    son[u]=0;
    for(i=Head[u];i!=-1;i=edge[i].next)
    {
        v=edge[i].v;
        if(v==fa[u])
          continue;
        depth[v]=depth[u]+1;
        fa[v]=u;
        dfs1(v);
        if(siz[v]>siz[son[u]])
          son[u]=v;
        siz[u]+=siz[v];
    }
}
void dfs2(int u,int f)
{
    int i,j,k,v;
    p[u]=++tot2;
    top[u]=f;
    if(son[u]!=0)
      dfs2(son[u],f);
    for(i=Head[u];i!=-1;i=edge[i].next)
    {
        v=edge[i].v;
        if(v==fa[u] || v==son[u])
          continue;
        dfs2(v,v);
    }
}
void add(int u,int v,int w)
{
    edge[tot].u=u;
    edge[tot].v=v;
    edge[tot].w=w;
    edge[tot].next=Head[u];
    Head[u]=tot++;
}
void up(int tr)
{
    tree[tr].maxn=max(tree[tr*2].maxn,tree[tr*2+1].maxn);
    tree[tr].minn=min(tree[tr*2].minn,tree[tr*2+1].minn);
}
void op(int tr)
{
    tree[tr].maxn=-tree[tr].maxn;
    tree[tr].minn=-tree[tr].minn;
    swap(tree[tr].maxn,tree[tr].minn);
}
void down(int tr)
{
    int minn,maxn;
    if(tree[tr].lazy)
    {
        tree[tr].lazy=0;
        tree[tr*2].lazy=(tree[tr*2].lazy+1)%2;
        tree[tr*2+1].lazy=(tree[tr*2+1].lazy+1)%2;
        op(tr*2);
        op(tr*2+1);
    }
}
void build(int l,int r,int tr)
{
    tree[tr].l=l;
    tree[tr].r=r;
    tree[tr].lazy=0;
    if(l==r)
    {
        tree[tr].maxn=tree[tr].minn=W[l];
        return;
    }
    int mi=(l+r)/2;
    build(l,mi,tr*2);
    build(mi+1,r,tr*2+1);
    up(tr);
}
void update1(int l,int r,int tr)
{
    if(tree[tr].l==l && tree[tr].r==r)
    {
        tree[tr].lazy=(tree[tr].lazy+1)%2;
        op(tr);
        return;
    }
    down(tr);
    int mi=(tree[tr].l+tree[tr].r)/2;
    if(r<=mi)
      update1(l,r,tr*2);
    else if(l>mi)
      update1(l,r,tr*2+1);
    else
    {
        update1(l,mi,tr*2);
        update1(mi+1,r,tr*2+1);
    }
    up(tr);
}
void update2(int id,int tr,int num)
{
    if(tree[tr].l==tree[tr].r)
    {
        tree[tr].maxn=tree[tr].minn=num;
        return;
    }
    down(tr);
    int mi=(tree[tr].l+tree[tr].r)/2;
    if(id<=mi)
      update2(id,tr*2,num);
    else
      update2(id,tr*2+1,num);
    up(tr);
}
int query(int l,int r,int tr)
{
    if(tree[tr].l==l && tree[tr].r==r)
      return tree[tr].maxn;
    down(tr);
    int mi=(tree[tr].l+tree[tr].r)/2;
    if(r<=mi)
      return query(l,r,tr*2);
    else if(l>mi)
      return query(l,r,tr*2+1);
    else
      return max(query(l,mi,tr*2),query(mi+1,r,tr*2+1));
}
int solve(int u,int v,int type)
{
    int f1=top[u],f2=top[v],k,maxn=-INF;
    while(f1!=f2)
    {
        if(depth[f1]<depth[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        if(type==1)
          update1(p[f1],p[u],1);
        else
          maxn=max(maxn,query(p[f1],p[u],1));
        u=fa[f1];
        f1=top[u];
    }
    if(u==v)
      return maxn;
    if(depth[u]>depth[v])
      swap(u,v);
    if(type==1)
      update1(p[son[u]],p[v],1);
    else
      maxn=max(maxn,query(p[son[u]],p[v],1));
    return maxn;
}
int main()
{
    int i,j,k,u,v,w,pos,ans;
    scanf("%d",&T);
    for(t=1;t<=T;t++)
    {
        scanf("%d",&n);
        tot=tot2=0;
        memset(Head,-1,sizeof(Head));
        for(i=1;i<n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            arr[i].u=u;
            arr[i].v=v;
            arr[i].w=w;
            add(u,v,w);
            add(v,u,w);
        }
        depth[1]=1;
        dfs1(1);
        dfs2(1,1);
        for(i=1;i<n;i++)
        {
            if(arr[i].v==fa[arr[i].u])
              swap(arr[i].v,arr[i].u);
            W[p[arr[i].v]]=arr[i].w;
        }
        build(1,tot2,1);
        while(true)
        {
            scanf("%s",s+1);
            if(s[1]=='C')
            {
                scanf("%d%d",&i,&w);
                update2(p[arr[i].v],1,w);
            }
            else if(s[1]=='N')
            {
                scanf("%d%d",&u,&v);
                solve(u,v,1);
            }
            else if(s[1]=='Q')
            {
                scanf("%d%d",&u,&v);
                ans=solve(u,v,2);
                printf("%d\n",ans);
            }
            else
              break;
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值