spoj 375 query on a tree 题解

题目大意:维护一棵树,支持查询两点间路径最大值,以及修改某边的权值。

裸的树链剖分+线段树。。不多说

这题卡常数卡的厉害啊!vector完全过不了

然后。。我就写了我一点都不熟悉的普通邻接表。

虽然代码丑,虽然依然很慢,虽然有点长,但是它至少A了。。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<vector>
  5 const int INF=~0U>>1;
  6 const int MAXN=10000+10;
  7 struct Edge{
  8     int u,v,cost;
  9     Edge() {}
 10     Edge(int u,int v,int cost):u(u),v(v),cost(cost) {}
 11 }edges[MAXN<<1];
 12 //std::vector<Edge> G[MAXN];
 13 int son[MAXN],dep[MAXN],w[MAXN],fa[MAXN],top[MAXN],sz[MAXN];
 14 int head[MAXN<<1],next[MAXN<<1];
 15 int dfs_clock;
 16 int n;
 17 inline void addedge(int u,int v,int cost,int edge)
 18 {
 19     edges[edge]=Edge(u,v,cost);
 20     next[edge]=head[u];
 21     head[u]=edge;
 22 }
 23 void dfs(int u)
 24 {
 25     sz[u]=1;son[u]=-1;
 26     for(int i=head[u];~i;i=next[i]) if(edges[i].v!=fa[u])
 27     {
 28         int v=edges[i].v;
 29         fa[v]=u;
 30         dep[v]=dep[u]+1;
 31         dfs(v);
 32         if(son[u]==-1 || sz[v]>sz[son[u]]) son[u]=v;
 33         sz[u]+=sz[v];
 34     }
 35 }
 36 void dfs2(int u,int tp)
 37 {
 38     w[u]=++dfs_clock;top[u]=tp;
 39     if(~son[u]) dfs2(son[u],tp);
 40     for(int i=head[u];~i;i=next[i]) if(edges[i].v!=fa[u] && edges[i].v!=son[u])
 41         dfs2(edges[i].v,edges[i].v);
 42 }
 43 int maxv[(1<<14)+10];
 44 int totn;
 45 void maintain(int o)
 46 {
 47     maxv[o]=std::max(maxv[o<<1],maxv[o<<1|1]);
 48 }
 49 void build(int o,int l,int r)
 50 {
 51     if(l==r) return;
 52     int m=l+r>>1;
 53     build(o<<1,l,m);
 54     build(o<<1|1,m+1,r);
 55     maxv[o]=std::max(maxv[o<<1],maxv[o<<1|1]);
 56 }
 57 int ask(int o,int l,int r,int x1,int x2)
 58 {
 59     if(r<x1 || l>x2) return -1;
 60     if(l>=x1 && r<=x2) return maxv[o];
 61     int m=l+r>>1;
 62     return std::max(ask(o<<1,l,m,x1,x2),ask(o<<1|1,m+1,r,x1,x2));
 63 }
 64 void update(int o,int l,int r,int x,int a)
 65 {
 66     if(l==r) maxv[o]=a;
 67     else
 68     {
 69         int m=l+r>>1;
 70         if(x<=m) update(o<<1,l,m,x,a);
 71         else update(o<<1|1,m+1,r,x,a);
 72         maintain(o);
 73     }
 74 }
 75 void init()
 76 {
 77     //memset(sz,0,sizeof(sz));
 78     //memset(maxv,-1,sizeof(maxv));
 79     memset(head,-1,sizeof(head));
 80     for(int i=0;i<=n;++i) sz[i]=0;
 81     dep[0]=0;
 82     dfs_clock=0;
 83     fa[0]=-1;
 84     int k=0;
 85     while((1<<k)<n) ++k;
 86     totn=1<<k;
 87     for(int i=0;i<=(totn<<1);++i) maxv[i]=-1;
 88 }
 89 int query(int u,int v)
 90 {
 91     int f1=top[u],f2=top[v],ans=-1;
 92     while(f1!=f2)
 93     {
 94         if(dep[f1]<dep[f2])
 95             std::swap(f1,f2),std::swap(u,v);
 96         ans=std::max(ans,ask(1,1,totn,w[f1],w[u]));
 97         u=fa[f1];f1=top[u];
 98     }
 99     if(u==v) return ans;
100     if(dep[u]<dep[v]) std::swap(u,v);
101     return std::max(ans,ask(1,1,totn,w[son[v]],w[u]));
102 }
103 int main()
104 {
105 //    freopen("1.in","r",stdin);
106     int T;
107     scanf("%d",&T);
108     while(T--)
109     {
110         scanf("%d",&n);
111         init();
112         for(int i=0;i<n-1;++i)
113         {
114             int u,v,cost;
115             scanf("%d%d%d",&u,&v,&cost);
116             --u;--v;
117             addedge(u,v,cost,i<<1);
118             addedge(v,u,cost,i<<1|1);
119         }
120         dfs(0);
121         dfs2(0,0);
122         for(int i=0;i<n-1;++i)
123         {
124             int u=edges[i<<1].u,v=edges[i<<1].v;
125             if(dep[u]>dep[v]) std::swap(u,v);
126             update(1,1,totn,w[v],edges[i<<1].cost);
127         }
128         char s[10];
129         while(scanf("%s",s)==1 && s[0]!=‘D‘)
130         {
131             if(s[0]==‘Q‘)
132             {
133                 int u,v;
134                 scanf("%d%d",&u,&v);
135                 --u;--v;
136                 printf("%d\n",query(u,v));
137             }
138             else
139             {
140                 int x,a;
141                 scanf("%d%d",&x,&a);
142                 --x;
143                 int u=edges[x<<1].u,v=edges[x<<1].v;
144                 if(dep[u]>dep[v]) std::swap(u,v);
145                 update(1,1,totn,w[v],a);
146             }
147         }
148     }
149     return 0;
150 }

时间: 2024-11-10 05:32:02

spoj 375 query on a tree 题解的相关文章

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. 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 (树链剖分)

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

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【树链剖分】

题目大意:给你一棵树,有两个操作1.修改一条边的值,2.询问从x到y路径上边的最大值 思路:如果树退化成一条链的话线段树就很明显了,然后这题就是套了个树连剖分,调了很久终于调出来第一个模板了 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define maxn 100009 5 using namespace std; 6 int head[maxn],next[maxn*2],point[

SPOJ - QTREE Query on a tree题解

题目大意: 一棵树,有边权,有两个操作:1.修改一条边的权值:2.询问两点间路径上的边的权值的最大值. 思路: 十分裸的树链剖分+线段树,无非是边权要放到深度大的一端的点上,但是有两个坑爹的地方,改了好久: 1.数组定义10000和40000会TLE,要乘10: 2.以前的树剖求解的最后是这样的: if (deep[x]>deep[y]) swap(x,y); return max(ans,MAX(1,n,id[x],id[y],1)); 但是WA了,膜拜大神后发现这样就AC了: if (x==

SPOJ 375 Query on a tree

Desciption 给出一个树,每条边有边权,支持两种操作,询问 \(u,v\) 路径上边权最大值,修改第 \(i\) 条边的边权,\(n\leqslant 10^4,T\leqslant 10\) Sol 树链剖分. 基于边的树链剖分,对于一个点,可能有许多儿子,但是它只能有一个父亲,给它编号表示它到它父亲的边,只需要修改查询的是最后一步就可以了. Code #include<cstdio> #include<vector> #include<iostream> u

SPOJ QTREE 375. Query on a tree

SPOJ Problem Set (classical) 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: CHA

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