【学术篇】SPOJ QTREE 树链剖分

发现链剖这东西好久不写想一遍写对是有难度的.. 果然是熟能生巧吧..
WC的dalao们都回来了 然后就用WC的毒瘤题荼毒了我们一波, 本来想打个T1 44分暴力 然后好像是特判写挂了还是怎么的就只能得28pts..

重新见到这些失踪的dalao灰常开心, 于是想让自己心情稍微差一点, 就想着把自己昨天写WA的QTREE重构一遍吧..
于是重构的sb链剖果然挂掉了... 出现了各种各样的漏洞... 忘记各种各样的句子, 然而退化成了暴力小数据也随便过看不出来啊~~~

但是还是在1h之内调对了_(:з」∠)_ 已经很满意了... 不过交的时候把自己的样例交上去还CE了一次orz...
就这样吧..

题目分析: 两种操作:

  1. 修改第\(i\)条边(输入顺序).
  2. 查询两个点\(u,v\)路径上边权的最大值.

链剖的话边权不是很好搞, 考虑采用之前学过的一种做法

连x->y边的时候可以拆成x->z->y的两条边啊,然后把边权放在z就可以了

这样处理完就变成了裸的单点改区间查, 随便套个线段树水一下就好了(说得轻巧, 你细节死成什么样自己心里没点数么= =

代码:

#include <cstdio>
#include <cstring>
const int N=202020;
inline int gn(int a=0,char c=0,int f=1){
    for(;(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-') f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar()) a=a*10+c-'0'; return a*f;
}
inline int max(const int& a,const int& b){
    return a>b?a:b;
}
struct edge{
    int to,next;
}e[N]; int v[N],tot;
void buildedge(int x,int y){
    e[++tot].to=y; e[tot].next=v[x]; v[x]=tot;
    e[++tot].to=x; e[tot].next=v[y]; v[y]=tot;
}
int fa[N],ez[N],d[N],sz[N];
void dfs1(int x){ ez[x]=x; sz[x]=1;
    for(int i=v[x];i;i=e[i].next){
        int y=e[i].to;
        if(fa[x]!=y){
            fa[y]=x; d[y]=d[x]+1; dfs1(y); sz[x]+=sz[y];
            if(ez[x]==x||sz[y]>sz[ez[x]]) ez[x]=y;
        }
    }
}
int pos[N],rank[N],tp[N],a[N>>1],ti;
void dfs2(int x,int tpx){
    tp[x]=tpx; pos[++ti]=x; rank[x]=ti;
    if(ez[x]!=x) dfs2(ez[x],tpx);
    for(int i=v[x];i;i=e[i].next){
        int y=e[i].to;
        if(y!=fa[x]&&y!=ez[x]) dfs2(y,y);
    }
}
int t[N<<2],n;
inline void update(int x){
    t[x]=max(t[x<<1],t[x<<1|1]);
}
void build(int x,int l,int r){
    if(l==r){
        t[x]=a[pos[++ti]];
        return;
    } int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    update(x);
}
void change(int x,int l,int r,int k,int s){
    if(l==r){
        t[x]=s; return;
    } int mid=(l+r)>>1;
    if(k<=mid) change(x<<1,l,mid,k,s);
    else change(x<<1|1,mid+1,r,k,s);
    update(x);
}
int query(int x,int l,int r,int L,int R){
    if(L<=l&&r<=R) return t[x];
    int mid=(l+r)>>1,ans=-0x7fffffff;
    if(L<=mid) ans=max(ans,query(x<<1,l,mid,L,R));
    if(R>mid) ans=max(ans,query(x<<1|1,mid+1,r,L,R));
    return ans;
}

inline int querya(int x,int y){ int ans=-0x7fffffff;
    while(tp[x]!=tp[y])
        if(d[tp[x]]>d[tp[y]]) ans=max(ans,query(1,1,n,rank[tp[x]],rank[x])),x=fa[tp[x]];
        else ans=max(ans,query(1,1,n,rank[tp[y]],rank[y])),y=fa[tp[y]];
    if(d[x]<d[y]) ans=max(ans,query(1,1,n,rank[x],rank[y]));
    else ans=max(ans,query(1,1,n,rank[y],rank[x]));
    return ans;
}

inline void init(){
    memset(a,192,sizeof(a));
    memset(v,0,sizeof(v));
    ti=tot=0;
}
inline void work(){ init();
    n=gn(); int nn=n; n=n*2-1;
    for(int i=1;i<nn;++i){
        int x=gn(),y=gn(),z=gn(); a[nn+i]=z;
        buildedge(x,nn+i); buildedge(nn+i,y);
    }
    dfs1(1); dfs2(1,1); fa[1]=1;
    ti=0; build(1,1,n);
    char c[10];
    while(1){
        scanf("%s",c); if(c[0]=='D') break;
        int x=gn(),y=gn();
        if(c[0]=='Q') printf("%d\n",querya(x,y));
        else change(1,1,n,rank[nn+x],y);
    }
}
int main(){
    int T=gn();
    while(T--)work();
}

原文地址:https://www.cnblogs.com/enzymii/p/8442597.html

时间: 2024-10-06 21:21:51

【学术篇】SPOJ QTREE 树链剖分的相关文章

SPOJ QTREE 树链剖分

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

SPOJ375.QTREE树链剖分

题意:一个树,a b c 代表a--b边的权值为c.CHANGE x y  把输入的第x条边的权值改为y,QUERY x y 查询x--y路径上边的权值的最大值. 第一次写树链剖分,其实树链剖分只能说是一种思想.树链剖分  就是 先选择从根节点到叶子节点的最长的路径的权值对应到线段树上,然后从一个子树的根节点到叶子的最长路径的权值对应到线段树上这样直到把所有的点都处理了,然后就是线段树区间查询最值了. 具体可以看这个博客.http://blog.sina.com.cn/s/blog_6974c8

SPOJ 375 树链剖分

点击打开链接 题意:给个树和树上的权值,两个操作,Q u v,问u到v的边上的最大权值,C u v,将第u条边的权值改为v 思路:今天学了学树链剖分,这题是个检验模版的题目,理论我是解释不清楚的,自己在九野聚聚那学来的一份模版 #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <a

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 - QTREE 375 Query on a tree 树链剖分+线段树

操作1:修改第k条边权. 操作2:询问两点间最大边权. 树链剖分,然后线段树维护最大值 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #inclu

SPOJ QTREE Query on a tree ——树链剖分 线段树

[题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 20005 int T,n,fr[maxn],h[maxn],to[maxn],ne[maxn]

树链剖分模板+入门题 SPOJ - QTREE

题目链接:[点击进入](http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=13013) 树链剖分并不是一个复杂的算法或者数据结构,只是能把一棵树拆成链来处理而已,换一种说法,树链剖分只是xxx数据结构/算法在树上的推广,或者说,树链剖分只是把树hash到了几段连续的区间上.比如说下面这道题,就是将树分为重链和轻链然后映射到线段树上,然后再在线段树上进行查询和修改等操作.所以树链剖分的重点有两个,一是正确的将树分解成几段并映射到

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