SPOJ 375 QTREE

题目链接:传送门

题目大意:给一棵无根树,树边有权值,有很多次操作,QUERY代表询问从 x 到 y 路径上的边的最大

     权值,CHANGE代表改变按输入顺序第 x 条边的权值为 y。 对于每个QUERY,输出一个答案。

题目思路:树链剖分(第一次学树链,还有点云里雾里的)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <cctype>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <climits>
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define fi first
#define se second
#define ping(x,y) ((x-y)*(x-y))
#define mst(x,y) memset(x,y,sizeof(x))
#define mcp(x,y) memcpy(x,y,sizeof(y))
using namespace std;
#define gamma 0.5772156649015328606065120
#define MOD 1000000007
#define inf 0x3f3f3f3f
#define N 10050
#define maxn 30010
typedef pair<int,int> PII;
typedef long long LL;
LL read(){
    LL x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=(x<<3)+(x<<1)+ch-‘0‘;ch=getchar();}
    return x*f;
}

int n,m,k,head[N],hcnt,rt;
char str[11];
struct Node{
    int to,nxt,v;
}node[maxn];
struct Edge{
    int x,y,v;
}edge[maxn];
int seg[N<<2];

int siz[N];  ///当前节点保存的儿子数
int top[N];  ///当前节点所在链的顶端节点
int son[N];  ///保存重儿子
int dep[N];  ///当前节点深度
int fa[N];   ///当前节点的父亲
int id[N];   ///用来保存树中每个节点剖分后的新编号
int posi[N]; ///在线段树中的位置
int tid,pos;

///树链剖分
void dfs1(int u,int f,int deep){ ///找重边
    dep[u]=deep;
    fa[u]=f;
    siz[u]=1;
    for(int i=head[u];~i;i=node[i].nxt){
        int e=node[i].to;
        if(e==f)continue;
        dfs1(e,u,deep+1);
        siz[u]+=siz[e];
        if(!son[u]||siz[son[u]]<siz[e])
            son[u]=e;
    }
}
void dfs2(int u,int tp){   ///连重边成重链
    top[u]=tp;
    id[u]=++tid;
    posi[id[u]]=u;
    if(!son[u])return;
    dfs2(son[u],tp);
    for(int i=head[u];~i;i=node[i].nxt){
        int e=node[i].to;
        if(e!=son[u]&&e!=fa[u])
            dfs2(e,e);
    }
}

///线段树
void build(int rt,int l,int r){
    seg[rt]=-inf;
    if(l==r) return;
    int mid=l+r>>1;
    build(lson); build(rson);
    seg[rt]=max(seg[rt<<1],seg[rt<<1|1]);
}

void add(int rt,int l,int r,int v){
    if(l==r){
        seg[rt]=v;
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid)add(lson,v);
    else add(rson,v);
    seg[rt]=max(seg[rt<<1],seg[rt<<1|1]);
}
int query(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R){return seg[rt];}
    int mid=l+r>>1;
    int temp=INT_MIN;
    if(L<=mid)temp=max(temp,query(lson,L,R));
    if(R>mid) temp=max(temp,query(rson,L,R));
    return temp;
}

void ini(){
    mst(head,-1);hcnt=tid=0;mst(seg,0);
    mst(son,0);mst(siz,0);
}
void add(int x,int y,int v){
    node[hcnt].to=y,node[hcnt].nxt=head[x],node[hcnt].v=v,head[x]=hcnt++;
    node[hcnt].to=x,node[hcnt].nxt=head[y],node[hcnt].v=v,head[y]=hcnt++;
}
int lca(int x,int y){
    int ans=-inf;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=max(ans,query(1,1,n,id[top[x]],id[x]));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x!=y)ans=max(ans,query(1,1,n,id[x]+1,id[y]));
    return ans;
}
int main(){
    //freopen("in.txt","r",stdin);
    int i,j,group,x,y,v,Case=0;
    group=read();
    while(group--){
        ini();
        n=read();
        for(i=1;i<n;++i){
            scanf("%d%d%d",&x,&y,&v);
            edge[i].x=x,edge[i].y=y,edge[i].v=v;
            add(x,y,v);
        }
        dfs1(1,1,1);
        dfs2(1,1);
        build(1,1,n);
        for(i=1;i<n;i++){
            if(dep[edge[i].x]<dep[edge[i].y])
                swap(edge[i].x,edge[i].y);
            pos=id[edge[i].x];
            add(1,1,n,edge[i].v);
        }
        while(scanf("%s",str)!=EOF){
            if(str[0]==‘D‘)break;
            x=read();y=read();
            if(str[0]==‘Q‘){
                printf("%d\n",lca(x,y));
            }
            else{
                pos=id[edge[x].x];
                add(1,1,n,y);
            }
        }
        printf("\n");
    }
    return 0;
}
时间: 2024-08-15 01:21:54

SPOJ 375 QTREE的相关文章

SPOJ 375 QTREE系列-Query on a tree (树链剖分)

题目地址:SPOJ 375 树链剖分第一发! 果然是个貌似很高级的数据结构,其实就是把树的边从树形结构转化成了线性结构,从而可以用线段树或树状数组之类的数据结构进行快速维护.从而将时间缩到n*log(2*n). 这题用的线段树维护的. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #incl

SPOJ 375 QTREE - Query on a tree(树链剖分)

题目链接:http://www.spoj.com/problems/QTREE/en/ 题意:  一棵树 n 个节点,每条边上有权值,同时有两个操作: (1)更改操作:CHANGE i ti(把第 i 条边上的权值改为 ti). (2)查询操作:QUERY a b(查询 a 到 b 的路径上权值最大的边的权值). 思路(树链剖分): 看到这种区间查询的题想要用数据结构优化,提高时间效率一般会想到线段树.可是这次操作的对象并不是一组序列, 无法直接使用线段树.这时,我们可以做些转化:对树作树链剖分

spoj 375 QTREE - Query on a tree 树链剖分

题目链接 给一棵树, 每条边有权值, 两种操作, 一种是将一条边的权值改变, 一种是询问u到v路径上最大的边的权值. 树链剖分模板. #include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set&g

spoj 375. Query on a tree 【树链剖分--插点问线 】

题目:spoj 375. Query on a tree 题意:题意很清晰,就是给你一颗树,每两点之间有权值,然后改变一些权值,问一条路径上的最大值. 分析:入门题目,直接套树链模板 AC代码: #include <cstdio> #include <algorithm> #include <iostream> #include <string.h> using namespace std; const int N = 10010; #define Del(

spoj 375 AND bzoj 1036 树链剖分

树链剖分的入门题目,自己写了下感觉还是挺好写的,不过真的有点长... spoj 375 边有权值: 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int INF = -999999999; 7 const int N = 10001; 8 int head[N]; 9 int sz[N]; 10 int depth[N]; 1

【树链剖分模板】【SPOJ 375】 Query on a tree

375. Query on a tree Problem code: QTREE You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of

SPOJ 375. Query on a tree (树链剖分)

Query on a tree Time Limit: 5000ms Memory Limit: 262144KB This problem will be judged on SPOJ. Original ID: QTREE64-bit integer IO format: %lld      Java class name: Main Prev Submit Status Statistics Discuss Next Font Size: + - Type:   None Graph Th

spoj 375 query on a tree LCT

这道题是树链剖分的裸题,正在学LCT,用LCT写了,发现LCT代码比树链剖分还短点(但我的LCT跑极限数据用的时间大概是kuangbin大神的树链剖分的1.6倍,所以在spoj上是850ms卡过的). 收获: 1.边转换成点(即若存在边(u,v),则新加一个点z代表边,将z连接u和v,z的点权就是(u,v)的边权,非边点的权设为-oo),然后对边权的统计就变成了对点权的统计(这是LCT中处理边信息的通法之一). 2.若要连接两个点u,v,先让它们分别称为根,然后将其中一个的path-parent

spoj 375 Query on a tree (树链剖分)

Query on a tree You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of the i-th edge to ti or Q