[POJ3237]Tree

题目描述 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 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 Description

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 Description

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

数据范围及提示 Data Size & Hint

 

之前的一些废话:是时候准备会考了。。

题解:树链剖分+线段树,其中tag[o]表示pushdown的时候儿子需不需要再次反转。

代码:

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
typedef long long LL;
#define mem(a,b) memset(a,b,sizeof(a))
typedef pair<int,int> PII;
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
const int maxn=10010,oo=2147483647;
int T,n,m,a,b,c,ce,es,first[maxn],deep[maxn],size[maxn],ms[maxn],fa[maxn],bl[maxn],id[maxn],Eid[maxn];
int A[maxn],Max[maxn<<2],Min[maxn<<2],tag[maxn<<2];
char s[5];
struct Edge
{
    int u,v,w,next;
    Edge() {}
    Edge(int _1,int _2,int _3,int _4):u(_1),v(_2),w(_3),next(_4) {}
}e[maxn<<1];
void addEdge(int a,int b,int c)
{
    e[++ce]=Edge(a,b,c,first[a]);first[a]=ce;
    e[++ce]=Edge(b,a,c,first[b]);first[b]=ce;
}
void rev(int o){int a=Max[o];Max[o]=-Min[o];Min[o]=-a;}
void pushdown(int l,int r,int o)
{
    int mid=(l+r)>>1,lo=o<<1,ro=lo|1;    
    if(l==r || !tag[o])return;
    tag[o]=0;tag[lo]^=1;tag[ro]^=1;
    rev(lo);rev(ro); 
}
void pushup(int l,int r,int o)
{
    int mid=(l+r)>>1,lo=o<<1,ro=lo|1;    
    Max[o]=max(Max[lo],Max[ro]);
    Min[o]=min(Min[lo],Min[ro]);
}
void build(int l,int r,int o)
{
    int mid=(l+r)>>1,lo=o<<1,ro=lo|1;    
    if(l==r)
    {
        Max[o]=Min[o]=A[l]; 
        return;
    }
    build(l,mid,lo);build(mid+1,r,ro);
    pushup(l,r,o);
}
void update(int l,int r,int o,int a,int b)
{
    int mid=(l+r)>>1,lo=o<<1,ro=lo|1;    
    if(l==r)
    {
        tag[o]=0;Min[o]=Max[o]=b;
        return;
    }
    pushdown(l,r,o);
    if(a>mid)update(mid+1,r,ro,a,b);
    else update(l,mid,lo,a,b);
    pushup(l,r,o);
}
void Negate(int l,int r,int o,int a,int b)
{
    int mid=(l+r)>>1,lo=o<<1,ro=lo|1;    
    if(l==a && r==b)
    {
        tag[o]^=1;rev(o);
        return;
    }
    pushdown(l,r,o);
    if(b<=mid)Negate(l,mid,lo,a,b);
    else if(a>mid)Negate(mid+1,r,ro,a,b);
    else Negate(l,mid,lo,a,mid),Negate(mid+1,r,ro,mid+1,b);
    pushup(l,r,o);
}
int query(int l,int r,int o,int a,int b)
{
    int mid=(l+r)>>1,lo=o<<1,ro=lo|1;    
    if(l==a && r==b)return Max[o];
    pushdown(l,r,o);
    if(b<=mid)return query(l,mid,lo,a,b);
    else if(a>mid)return query(mid+1,r,ro,a,b);
    else return max(query(l,mid,lo,a,mid),query(mid+1,r,ro,mid+1,b));
}
void dfs(int now,int pa)
{
    size[now]=1;
    for(int i=first[now];i!=-1;i=e[i].next)
        if(e[i].v!=pa)
        {
            fa[e[i].v]=now;deep[e[i].v]=deep[now]+1;
            dfs(e[i].v,now);
            size[now]+=size[e[i].v];
            if(size[e[i].v]>size[ms[now]])ms[now]=e[i].v;
        }
}
void divide(int now,int chain)
{
    id[now]=++es;bl[now]=chain;
    if(ms[now])divide(ms[now],chain);
    for(int i=first[now];i!=-1;i=e[i].next)
        if(e[i].v!=fa[now])
        {
            if(e[i].v!=ms[now])divide(e[i].v,e[i].v);
            Eid[(i+2)>>1]=e[i].v;A[id[e[i].v]]=e[i].w;
        }
}
int lca(int a,int b)
{
    while(bl[a]!=bl[b])
    {
        if(deep[bl[a]]<deep[bl[b]])swap(a,b);
        a=fa[bl[a]];
    }
    return deep[a]<deep[b] ? a : b;
}
void change(int a,int b)
{
    while(bl[a]!=bl[b])
    {
        if(deep[bl[a]]<deep[bl[b]])swap(a,b);
        Negate(1,n,1,id[bl[a]],id[a]);
        a=fa[bl[a]];
    }
    if(id[b]+1<=id[a])Negate(1,n,1,id[b]+1,id[a]);
}
int ask(int a,int b)
{
    int ans=-oo;
    while(bl[a]!=bl[b])
    {
        if(deep[bl[a]]<deep[bl[b]])swap(a,b);
        ans=max(ans,query(1,n,1,id[bl[a]],id[a]));
        a=fa[bl[a]];
    }
    if(id[b]+1<=id[a])ans=max(ans,query(1,n,1,id[b]+1,id[a]));
    return ans;
}
int main()
{
    T=read();
    while(T--)
    {
        mem(first,-1);mem(e,0);mem(fa,0);mem(deep,0);mem(size,0);mem(ms,0);mem(bl,0);mem(id,0);mem(Eid,0);
        mem(A,0);mem(Max,0);mem(Min,0);mem(tag,0);ce=-1;es=0;
        n=read();
        for(int i=1;i<n;i++)a=read(),b=read(),c=read(),addEdge(a,b,c);
        dfs(1,-1);divide(1,1);build(1,n,1);
        while(1)
        {
            scanf("%s",s);
            if(s[0]=='D')break;
            a=read();b=read();
            if(s[0]=='C')update(1,n,1,id[Eid[a]],b);
            if(s[0]=='N')
            {
                int c=lca(a,b);
                change(a,c);change(b,c);
            }
            if(s[0]=='Q')
            {
                int c=lca(a,b);
                printf("%d\n",max(ask(a,c),ask(b,c)));
            }
        }
    }
    return 0;
}
View Code

总结:线段树的细节一定要想明白再写,最好先把线形的写好,并且对拍无误再上树。

posted @ 2017-06-21 18:06  小飞淙的云端  阅读(111)  评论(0编辑  收藏  举报