关闭

POJ 3237 Tree (树链剖分+线段树)

474人阅读 评论(0) 收藏 举报
分类:

POJ 3237 Tree

题目大意:

给你n个结点的树,有三种操作:
1.CHANGE i v 将i号边边权变为v
2.NEGATE a b 将a点到b点路径上的边权取相反数
3.QUERY a b 找到a点到b点路径上的边权的最大值
输出所有3操作结果,指令结束标志为”DONE”.
有多组数据.

题目分析:

(又滚去做树链剖分的题,元旦放假前开始做到现在,233)

将边权转化成相连两点中子节点的点权,根无权值.

第一个操作,单点修改;第三个操作,区间最值.
主要是第二个操作,区间取相反数.

维护区间的max和min,便于取反操作.
对于每一个取反操作,区间加标记,交换max和min的值,并且max,min取其相反数.
但是需要注意,线段树的所有操作都要考虑标记的下放,之前没注意这个,WA了.

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int maxn=10000+10;
const int maxm=20000+10;
const int INF=(1<<30);

int fir[maxn],nxt[maxm],to[maxm],ecnt;

void add_edge(int u,int v)
{
    nxt[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;
    nxt[++ecnt]=fir[v];fir[v]=ecnt;to[ecnt]=u;
}

int fa[maxn],sz[maxn],son[maxn];

void dfs1(int u,int p)
{
    fa[u]=p;sz[u]=1;son[u]=0;
    for(int i=fir[u];i;i=nxt[i]) if(to[i]!=p) {
        int v=to[i];
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[v]>sz[son[u]]) son[u]=v;
    }
}

int top[maxn],dep[maxn],idx[maxn],id;

void dfs2(int u,int t,int d)
{
    top[u]=t;dep[u]=d;idx[u]=++id;
    if(son[u]) dfs2(son[u],t,d+1);
    for(int i=fir[u];i;i=nxt[i])
        if(to[i]!=fa[u]&&to[i]!=son[u]) dfs2(to[i],to[i],d+1);
}

struct Edge {
    int u,v,w;
    Edge(){}
    Edge(int u,int v,int w):u(u),v(v),w(w){}
}tmp[maxn];

#define lc (x<<1)
#define rc (x<<1|1)
#define mid ((l+r)>>1)

int val[maxn],maxs[maxn<<2],mins[maxn<<2],tag[maxn<<2];

void negat(int x)//取反操作 
{
    tag[x]^=1;
    swap(maxs[x],mins[x]);
    maxs[x]*=-1;mins[x]*=-1;
}

void put_down(int x)//标记下方 
{
    if(!tag[x]) return ;
    negat(lc);negat(rc);
    tag[x]=0;
}

void put_up(int x)
{
    maxs[x]=max(maxs[lc],maxs[rc]);
    mins[x]=min(mins[lc],mins[rc]);
}

void build(int x,int l,int r)
{
    if(l==r) maxs[x]=mins[x]=val[l];
    else {
        build(lc,l,mid);
        build(rc,mid+1,r);
        put_up(x);
    }
}

void change(int x,int l,int r,int q,int v)//单点修改 
{
    if(l==r&&l==q) {
        maxs[x]=mins[x]=v;
        return ;
    }
    put_down(x);//单点修改时也应将标记下放 
    if(q<=mid) change(lc,l,mid,q,v);
    else change(rc,mid+1,r,q,v);
    put_up(x);
}

void update(int x,int l,int r,int ql,int qr)//区间取反 
{
    if(ql<=l&&r<=qr) {
        negat(x);
        return ;
    }
    put_down(x);
    if(ql<=mid) update(lc,l,mid,ql,qr);
    if(qr>mid) update(rc,mid+1,r,ql,qr);
    put_up(x);
}

int query(int x,int l,int r,int ql,int qr)//区间最值 
{
    if(ql<=l&&r<=qr) return maxs[x];
    int L=-INF,R=L;
    put_down(x);
    if(ql<=mid) L=query(lc,l,mid,ql,qr);
    if(qr>mid) R=query(rc,mid+1,r,ql,qr);
    return max(L,R);
}

int n;

void solve(int x,int y,int k)//k 0 NEGATE 1 QUERY
{
    int ret=-INF;
    while(top[x]!=top[y]) {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        if(k) ret=max(ret,query(1,2,n,idx[top[x]],idx[x]));
        else update(1,2,n,idx[top[x]],idx[x]);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    if(idx[y]>idx[x]) {
        if(k) ret=max(ret,query(1,2,n,idx[x]+1,idx[y]));
        else update(1,2,n,idx[x]+1,idx[y]);
    }
    if(k) printf("%d\n",ret);
}

void init()//多组数据记得初始化 
{
    ecnt=id=0;
    memset(fir,0,sizeof(fir));
    memset(tag,0,sizeof(tag));
}

char op[10];

int main()
{
    int T,a,b;
    scanf("%d",&T);
    while(T--) {
        init();
        scanf("%d",&n);
        for(int u,v,w,i=1;i<n;i++) {
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v);
            tmp[i]=Edge(u,v,w);
        }
        dfs1(1,1);
        dfs2(1,1,1);
        for(int i=1;i<n;i++) {//边权转化成点权 
            int u=tmp[i].u,v=tmp[i].v;
            int f=dep[u]>dep[v]?u:v;
            val[idx[f]]=tmp[i].w;
            tmp[i].u=f;
        }
        build(1,2,n);
        while(scanf("%s",op)==1&&op[0]!='D') {
            scanf("%d%d",&a,&b);
            if(op[0]=='C') change(1,2,n,idx[tmp[a].u],b);
            else solve(a,b,op[0]=='N'?0:1);
        }
    }
    return 0;
}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:14508次
    • 积分:830
    • 等级:
    • 排名:千里之外
    • 原创:70篇
    • 转载:0篇
    • 译文:0篇
    • 评论:4条
    友情链接