POJ 3237 树链剖分

点击打开链接

题意:给一个树,三种操作,一个是将第I条边的权值改变,一个是将u到v的所有边的权值取反,一个是询问u到v的路径中边的最大值

思路:和模版的树链剖分没什么区别,这题唯一的坑点就是线段树的懒惰标记,只要有更新操作或者查询操作就都要pushdown(),然后改权值的比较简单,单点更新,而区间取反我们可以用两个数组直接模拟,一个最大值的,一个区间最小值的,然后一旦取反了,就将最大值改为负的最小值,而最小值一样改为负的最大值就可以了

#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fll;
const int maxn=100010;
int fa[maxn],siz[maxn],son[maxn],w[maxn],p[maxn],dep[maxn],fp[maxn],head[maxn];
//fa为父节点,siz为子节点中siz最大的,dep为深度,son为重儿子,w表示在线段树中的位置
int min1[maxn<<2],lazy[maxn<<2],max1[maxn<<2];
int tree_id,n,kkk=0;
struct node{
    int to,next;
}EE[maxn*10];
void add_edge(int u,int v){
    EE[kkk].to=v;EE[kkk].next=head[u];head[u]=kkk++;
}
void dfs1(int u,int ff,int deep){
    son[u]=0;fa[u]=ff;siz[u]=1;dep[u]=deep;
    for(int i=head[u];i!=-1;i=EE[i].next){
        int v=EE[i].to;
        if(v==ff) continue;
        dfs1(v,u,deep+1);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]]) son[u]=v;
    }
}
void dfs2(int u,int ff){
    w[u]=++tree_id;p[u]=ff;
    if(son[u]) dfs2(son[u],ff);
    else return ;
    for(int i=head[u];i!=-1;i=EE[i].next){
        int v=EE[i].to;
        if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
    }
}
void pushup(int node){
    max1[node]=max(max1[node<<1],max1[node<<1|1]);
    min1[node]=min(min1[node<<1],min1[node<<1|1]);
}
void pushdown(int node){
    if(lazy[node]){
        lazy[node<<1]^=1;
        lazy[node<<1|1]^=1;
        int tmp=max1[node<<1];max1[node<<1]=-min1[node<<1];min1[node<<1]=-tmp;
        tmp=max1[node<<1|1];max1[node<<1|1]=-min1[node<<1|1];min1[node<<1|1]=-tmp;
        lazy[node]=0;
    }
}
void update(int pos,int val,int le,int ri,int node){
    if(le==ri){
        max1[node]=min1[node]=val;
        lazy[node]=0;
        return ;
    }
    pushdown(node);
    int t=(le+ri)>>1;
    if(pos<=t) update(pos,val,le,t,node<<1);
    else update(pos,val,t+1,ri,node<<1|1);
    pushup(node);
}
void update1(int l,int r,int le,int ri,int node){
    if(l<=le&&ri<=r){
        lazy[node]^=1;
        int tmp=max1[node];max1[node]=-min1[node];min1[node]=-tmp;
        return ;
    }
    pushdown(node);
    int t=(le+ri)>>1;
    if(l<=t) update1(l,r,le,t,node<<1);
    if(r>t) update1(l,r,t+1,ri,node<<1|1);
    pushup(node);
}
int query(int l,int r,int le,int ri,int node){
    if(l<=le&&ri<=r) return max1[node];
    pushdown(node);
    int t=(le+ri)>>1,ans=-inf;
    if(l<=t) ans=max(ans,query(l,r,le,t,node<<1));
    if(r>t) ans=max(ans,query(l,r,t+1,ri,node<<1|1));
    return ans;
}
int getmax(int u,int v){
    int f1=p[u],f2=p[v],tmp=-inf;
    while(f1!=f2){
        if(dep[f1]<dep[f2]){
            swap(f1,f2);
            swap(u,v);
        }
        tmp=max(tmp,query(w[f1],w[u],1,n,1));
        u=fa[f1];f1=p[u];
    }
    if(u==v) return tmp;
    if(dep[u]>dep[v]) swap(u,v);
    return max(tmp,query(w[son[u]],w[v],1,n,1));
}
void getupdate(int u,int v){
    int f1=p[u],f2=p[v];
    while(f1!=f2){
        if(dep[f1]<dep[f2]){
            swap(f1,f2);
            swap(u,v);
        }
        update1(w[f1],w[u],1,n,1);
        u=fa[f1];f1=p[u];
    }
    if(u==v) return ;
    if(dep[u]>dep[v]) swap(u,v);
    update1(w[son[u]],w[v],1,n,1);
}
int U[maxn],V[maxn],C[maxn];
int main(){
    int u,v,q,s,T;
    char str[10];
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        memset(head,-1,sizeof(head));
        memset(son,0,sizeof(son));tree_id=0;kkk=0;
        for(int i=0;i<n-1;i++){
            scanf("%d%d%d",&U[i],&V[i],&C[i]);
            add_edge(U[i],V[i]);add_edge(V[i],U[i]);
        }
        dfs1(1,1,0);
        dfs2(1,1);
        memset(max1,0,sizeof(max1));
        memset(min1,0,sizeof(min1));
        memset(lazy,0,sizeof(lazy));
        for(int i=0;i<n-1;i++){
            if(dep[U[i]]>dep[V[i]]) swap(U[i],V[i]);
            update(w[V[i]],C[i],1,n,1);
        }
        while(1){
            scanf("%s",&str);
            if(str[0]=='D') break;
            if(str[0]=='C'){
                scanf("%d%d",&u,&v);
                update(w[V[u-1]],v,1,n,1);
            }else if(str[0]=='Q'){
                scanf("%d%d",&u,&v);
                printf("%d\n",getmax(u,v));
            }else if(str[0]=='N'){
                scanf("%d%d",&u,&v);
                getupdate(u,v);
            }
        }
    }
    return 0;
}
时间: 2024-08-10 19:55:28

POJ 3237 树链剖分的相关文章

poj 3237 树链剖分(区间更新,区间查询)

http://poj.org/problem?id=3237 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 instruction

POJ 3237 /// 树链剖分 线段树区间修改(*-1)

题目大意: 给定树的N个结点 编号为1到N 给定N-1条边的边权. 三种操作: CHANGE k w:将第 k 条边的权值改成 w. NEGATE x y:将x到y的路径上所有边的权值乘 -1. QUERY x y:找出x到y的路径上所有边的最大权值. 单点更新 区间更新  区间查询 由于第二个操作是乘 -1 所以需要同时维护最大值和最小值 所以 lazy用来标记是否乘-1 0表示不乘-1 1表示乘-1 http://www.cnblogs.com/HDUjackyan/p/9279777.ht

poj 2763 树链剖分(单点更新,区间求值)

http://poj.org/problem?id=2763 Description After their royal wedding, Jiajia and Wind hid away in XX Village, to enjoy their ordinary happy life. People in XX Village lived in beautiful huts. There are some pairs of huts connected by bidirectional ro

POJ 2763 (树链剖分+边修改+边查询)

题目链接:http://poj.org/problem?id=2763 题目大意:某人初始在s点.有q次移动,每次移动沿着树上一条链,每经过一条边有一定花费,这个花费可以任意修改.问每次移动的花费. 解题思路: 树链剖分基础题.每次Q之后改变一下s. 线段树记录的是边权.方法是对于一条边(u,v),边权值加在dep比较大的那一端. 链查询(边)和 链查询(点)在轻链时略有不同. 注意本题使用vector邻接表存图是会TLE的,应该使用链式前向星.树链剖分中使用链式前向星是基本要求. #inclu

POJ 2763 树链剖分

点击打开链接 题意:给一个树,然后树上的边的边权,然后两个操作,一个是询问u到v的路上权值和,一个是将第几条边的权值修改 思路:与SPOJ 375 的那道题目很像,都是边上的权值,然后维护一个线段树进行修改和求和就行了 #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algor

POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)

题目链接:http://poj.org/problem?id=3237 一棵有边权的树,有3种操作. 树链剖分+线段树lazy标记.lazy为0表示没更新区间或者区间更新了2的倍数次,1表示为更新,每次更新异或1就可以. 熟悉线段树成段更新就很简单了,最初姿势不对一直wa,还是没有彻底理解lazy标记啊. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace st

cogs 1583. [POJ 3237] 树的维护 树链剖分套线段树

1583. [POJ 3237] 树的维护 ★★★★   输入文件:maintaintree.in   输出文件:maintaintree.out   简单对比时间限制:5 s   内存限制:128 MB [题目描述] 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1到N-1.每一条边有一个权值.然后你要在树上执行一系列指令.指令可以是如下三种之一: CHANGE i v:将第i条边的权值改成v. NEGATE a b:将点a到点b路径上所有边的权值变成其相反数. QUERY a b

poj 3237 Tree(树链剖分,线段树)

Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7268   Accepted: 1969 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

poj 3237 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