QTREE----树剖

题目内容:

————————————————————————————————————————————————————

Query on a tree

Time Limit: 851MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu

Submit Status

Description

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
  • QUERY a b : ask for the maximum edge cost on the path from node a to node b

Input

The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.

For each test case:

  • In the first line there is an integer N (N <= 10000),
  • In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between ab of cost c (c <= 1000000),
  • The next lines contain instructions "CHANGE i ti" or "QUERY a b",
  • The end of each test case is signified by the string "DONE".

There is one blank line between successive tests.

Output

For each "QUERY" operation, write one integer representing its result.

Example

Input:
1

3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

Output:
1
3

——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

第一次写树剖,好长时间写的代码,可是卡了,又过了好长时间才调,又调了好长时间才过。昨天刚刚调试成功。笨啊!!!!!!!!!!!!

树链剖分:就是把树剖成链。1、剖的依据为子树的大小。最大的为重儿子,其它的为轻儿子。连接重儿子的边为重边,其它的为轻边。重边组成重链。2、把重链依次放入线段树中,进行维护。

编程过程:

1、读入图(边表)。2、第一次DFS,维护树中各个点的深度、父亲、子树大小、重儿子。3、第二次DFS,维护树中各个链的顶节点,和各个节点在线段树中的位置。4、建空线段树。5、依次读取各条边(因为边表每边读取2边,所以要隔一条读一条),调整U,V的次序,保证边权落在子节点上,更新子节点在线段树中的位置。6、读取到更新命令时,依照(5)中的方法更新,但是因为U、V的次序已经调整,则无需调整,只需要更新边2*x-1的子节点即可。7、读取到查询命令时,首先判断两点是否在一条链上,(a)如果不,查询深度更深的点到它所在链的链顶的最大值,然后让该点更新为链顶点的父亲,并更新链顶继续判断,直到在一条链上为止。(b)如果在一条链上则,2点是否为同一点,如果是则直接返回,否则调整U、v两点的位置,查询u在线段树中位置+1(因为U点代表U上边的边)到v的位置的最大值,更新ans,返回输出。
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4
  5 using namespace std;
  6 struct edge
  7 {
  8     int u,v,w,next;
  9 }e[20010];
 10 struct node
 11 {
 12     int l,r,val;
 13     node * lc,* rc;
 14 }*root=NULL;
 15 int t,n;
 16 int head[10010],js,p;
 17 int fa[10010],son[10010],dep[10010],top[10010],siz[10010],fpos[10010],pos[10010];
 18 void init()
 19 {
 20     js=0;
 21     memset(head,0,sizeof(head));
 22     p=0;
 23     memset(e,0,sizeof(e));
 24     memset(son,0,sizeof(son));
 25 }
 26 void addage(int u,int v,int w)
 27 {
 28     e[++js].u=u;e[js].v=v;e[js].w=w;
 29     e[js].next=head[u];head[u]=js;
 30 }
 31 void dfs(int u,int f,int d)//?????????????????
 32 {
 33     fa[u]=f;dep[u]=d;siz[u]=1;
 34     for(int i=head[u];i;i=e[i].next)
 35     {
 36         int v=e[i].v;
 37         if(v!=f)
 38         {
 39             dfs(v,u,d+1);
 40             siz[u]+=siz[v];
 41             if(!son[u]||siz[son[u]]<siz[v])
 42             son[u]=v;
 43         }
 44     }
 45 }
 46 void getpos(int u,int tp)//??top,pos(????????)
 47 {
 48     top[u]=tp;
 49     pos[u]=++p;
 50 //    fpos[pos[u]]=u;
 51     if(!son[u])return;
 52     getpos(son[u],tp);
 53     for(int i=head[u];i;i=e[i].next)
 54     {
 55         int v=e[i].v;
 56         if(v!=son[u]&&v!=fa[u])
 57             getpos(v,v);
 58     }
 59 }
 60 void build(node * &pt,int l,int r)
 61 {
 62     pt=new(node);
 63     pt->l=l;pt->r=r;pt->val=0;
 64     if(l==r)
 65     {
 66         pt->lc=pt->rc=NULL;
 67         return ;
 68     }
 69     int mid=(l+r)/2;
 70     build(pt->lc,l,mid);
 71     build(pt->rc,mid+1,r);
 72 }
 73 void update(node * p,int ps,int val)
 74 {
 75     if(p->l==p->r)
 76     {
 77         p->val=val;
 78         return ;
 79     }
 80     int mid=(p->l+p->r)/2;
 81     if(ps<=mid)update(p->lc,ps,val);
 82     else update(p->rc,ps,val);
 83     p->val=max(p->lc->val,p->rc->val);
 84 }
 85 int query(node * p,int l,int r)
 86 {
 87     if(l<=p->l&&p->r<=r)return p->val;
 88     int mid=(p->l+p->r)/2;
 89     int ans=0;
 90     if(l<=mid)ans=max(ans,query(p->lc,l,r));
 91     if(r>mid)ans=max(ans,query(p->rc,l,r));
 92     return ans;
 93 }
 94 int find(int u,int v)
 95 {
 96     int tp1=top[u],tp2=top[v],ans=0;
 97     while(tp1!=tp2)
 98     {
 99         if(dep[tp1]<dep[tp2])
100         {
101             swap(tp1,tp2);
102             swap(u,v);
103         }
104         ans=max(ans,query(root,pos[tp1],pos[u]));
105         u=fa[tp1];tp1=top[u];
106     }
107     if(u==v)return ans;
108     if(dep[u]>dep[v])swap(u,v);
109     return max(ans,query(root,pos[u]+1,pos[v]));
110 }
111 int main()
112 {
113     cin>>t;
114     while(t--)
115     {
116         init();
117         scanf("%d",&n);
118         for(int i=1;i<n;i++)
119         {
120             int a,b,c;
121             scanf("%d%d%d",&a,&b,&c);
122             addage(a,b,c);
123             addage(b,a,c);
124         }
125         dfs(1,0,1);
126         getpos(1,1);
127         build(root,1,p);
128         for(int i=1;i<2*n-2;i+=2)
129         {
130             if(dep[e[i].v]<dep[e[i].u])swap(e[i].v,e[i].u);
131             update(root,pos[e[i].v],e[i].w);
132 //            cout<<e[i].u<<"------"<<e[i].v<<"-----"<<endl;
133         }
134         char s[10];
135         int u,v;
136         while(scanf("%s",s)==1)
137         {
138             if(s[0]==‘D‘)break;
139             scanf("%d%d",&u,&v);
140             if(s[0]==‘Q‘)printf("%d\n",find(u,v));
141             else update(root,pos[e[u*2-1].v],v);
142         }
143     }
144     return 0;
145 }
时间: 2024-11-05 22:06:21

QTREE----树剖的相关文章

SP375 QTREE - Query on a tree (树剖)

题目 SP375 QTREE - Query on a tree 解析 也就是个蓝题,因为比较长 树剖裸题(基本上),单点修改,链上查询. 可以看到这个题然我们对边进行操作,我们的树剖是对节点进行操作的,所以我们考虑把边权转移到点权上. 发现我们节点的点权是连向它的边的边权,所以我们要修改或查询边权的话,我们修改或查询的实际上是其连向点的点权, 假设我们要修改1-4之间的这两条边 我们修改的实际上就是这两个点 所以我们链上修改或查询的时候,不要修改或查询深度较浅的节点. 然后这是SPOJ上的题,

Codeforces 165D Beard Graph 边权树剖+树状数组

Beard Graph 题意:给你一颗由n个结点组成的树,支持以下操作:1 i:将第i条边染成黑色(保证此时该边是白色),2 i:将第i条边染成白色(保证此时该边是黑色),3 a b:找出a,b两点之间只由黑边组成的最短路径. 思路:树链剖分+树状数组,把每条边的权值放到它指向的点中去,初始全为黑边,黑边权值为1,白边权值为-inf,黑边变白边,将点权增加-inf,白边变黑边点权增加inf,因为不可能白边边白边,所以可以这样做,查询的时候要减去2个点的最近公共祖先的点权,最近公共祖先可通过树剖的

最近公共祖先(LCA)问题的树剖实现 (模板)

我来存个档,防止忘记!2333 传送门:https://daniu.luogu.org/problem/show?pid=3379 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输

LCA[倍增][树剖][tarjan]

LCA:最近公共祖先 倍增: 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 using namespace std; 6 #define N 105 7 int deep[N],dad[N][21]; 8 vector<int>vec[N]; 9 int lca(int x,int y) { 10 if(deep[x]>dee

【BZOJ3626】【LNOI2014】LCA (树剖+离线)

Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)].(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)答案对201314取模. 这个题是大饺子安利给我的,然后顺带学了一发树剖(好弱啊). 这个题解讲的很好啦w:http://www.cnbl

树剖注意要点

最近填坑刷题怒刷一堆树链剖分,得到一些心得 1.在build的时候需要计算的有h fa size,另外还有常规的son bro 2.为方便起见,build写成int,返回这棵子树的节点数 3.pou的时候如果发现没有子节点立刻返回(mdzz这都能忘记) 4.为习惯起见,build的时候传入的父亲用fat代表比较好,避免和习惯上用的fa重名:pou的时候传入的顶用to,避免和习惯上用的top重名 5.树剖的时候比较的是top的深度,较深的向上跑(...脑补能力缺陷晚期...)

HDU 6162 Ch’s gift (树剖 + 离线线段树)

Ch’s gift Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 662    Accepted Submission(s): 229 Problem Description Mr. Cui is working off-campus and he misses his girl friend very much. After a wh

BZOJ4034 树上操作(树剖 线段树大模板)

BZOJ4034 long long 是大坑点 貌似long long 跟int 乘起来会搞事情?... A了这题线段树和树剖的基础OK 嘛 重点过掉的还是线段树区间更新的lazy tag吧 #include<cstdio> #include<cstring> #define N 100001 using namespace std; struct ed{ int nxt,to; }e[N*2]; int ne=0,head[N]; long long int w0[N]; str

51nod1307(暴力树剖/二分&amp;dfs/并查集)

题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1307 题意: 中文题诶~ 思路: 解法1:暴力树剖 用一个数组 num[i] 维护编号为 i 的边当前最大能承受的重量. 在加边的过程中根据给出的父亲节点将当前边所在的链上所有边的num都减去当前加的边的重量, 注意当前边也要减自重. 那么当num首次出现负数时加的边号即位答案: 事实上这个算法的时间复杂度是O(n^2)的, 不过本题并没有出那种退化成单链的

poj3728The merchant树剖+线段树

如果直接在一条直线上,那么就建线段树 考虑每一个区间维护最小值和最大值和答案,就符合了合并的条件,一个log轻松做 那么在树上只要套一个树剖就搞定了,多一个log也不是问题 注意考虑在树上的话每一条链都有可能是正着被用和反着被用,所以存两个答案 所以维护信息只需要一个merge和一个reverse 代码如下: 1 #include <cstdio> 2 #include <iostream> 3 #define mid (l+r>>1) 4 using namespac