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 a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:

CHANGE i v Change the weight of the ith edge to v
NEGATE a b Negate the weight of every edge on the path from a to b
QUERY a b Find the maximum weight of edges on the path from a to b

Input

The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.

Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N − 1 lines each contains three integers a, b and c, describing an edge connecting nodes a and b with weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE” ends the test case.

Output

For each “QUERY” instruction, output the result on a separate line.

Sample Input

1

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

Sample Output

1
3

Source

POJ Monthly--2007.06.03, Lei, Tao

【思路】

树链剖分,线段树。

又练了一边线段树<_<,bug满天飞T^T,线段树还得再做点题。

线段树:维护mx mn分别代表线段最大最小值,对于NEGATE操作打一个f标记,作用时直接将mx mn取负后交换即可。注意一下pushdown和maintain。

【代码】

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<iostream>
  5 #include<algorithm>
  6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
  7 using namespace std;
  8
  9 const int N = 50000+10;
 10 const int INF = 1e9;
 11
 12 struct Node { int l,r,mx,mn,f;
 13 }T[N<<1];
 14 struct Edge {
 15     int u,v,w;
 16     Edge(int u=0,int v=0,int w=0) :u(u),v(v),w(w) {};
 17 };
 18 int n,q,z,d[N][3];
 19 vector<Edge> es;
 20 vector<int> g[N];
 21
 22 void adde(int u,int v,int w) {
 23     es.push_back(Edge(u,v,w));
 24     int m=es.size();
 25     g[u].push_back(m-1);
 26 }
 27 //INIT
 28 int top[N],son[N],dep[N],fa[N],siz[N],w[N];
 29 void dfs1(int u) {
 30     son[u]=0; siz[u]=1;
 31     for(int i=0;i<g[u].size();i++) {
 32         int v=es[g[u][i]].v;                                //1
 33         if(v!=fa[u]) {
 34             fa[v]=u , dep[v]=dep[u]+1;
 35             dfs1(v);
 36             siz[u]+=siz[v];
 37             if(siz[v]>siz[son[u]]) son[u]=v;
 38         }
 39     }
 40 }
 41 void dfs2(int u,int tp) {
 42     top[u]=tp; w[u]=++z;
 43     if(son[u]) dfs2(son[u],tp);
 44     for(int i=0;i<g[u].size();i++) {
 45         int v=es[g[u][i]].v;
 46         if(v!=fa[u] && v!=son[u]) dfs2(v,v);
 47     }
 48 }
 49 //SEGMENT TREE
 50 //标记 该结点已被作用而子结点仍未作用
 51 //pushdown 作用于访问节点 即只要访问就pushdown
 52 void pushdown(int u) {    //下传标记 同时作用于子结点
 53     if(T[u].f && T[u].l<T[u].r) {
 54         int lc=u<<1,rc=lc|1;
 55         T[u].f=0;
 56         T[lc].f^=1 ,T[rc].f^=1;
 57         int t;
 58         t=T[lc].mn,T[lc].mn=-T[lc].mx,T[lc].mx=-t;
 59         t=T[rc].mn,T[rc].mn=-T[rc].mx,T[rc].mx=-t;
 60     }
 61 }
 62 void maintain(int u) {
 63     T[u].mx=max(T[u<<1].mx,T[u<<1|1].mx);
 64     T[u].mn=min(T[u<<1].mn,T[u<<1|1].mn);
 65 }
 66 void build(int u,int L,int R) {
 67     T[u].l=L,T[u].r=R;
 68     T[u].mn=INF , T[u].mx=-INF , T[u].f=0;
 69     if(L==R) return ;                                        //2
 70     int M=(L+R)>>1;
 71     build(u<<1,L,M) , build(u<<1|1,M+1,R);
 72 }
 73 void change(int u,int r,int x) {
 74     pushdown(u);                                            //6
 75     if(T[u].l==T[u].r) T[u].mn=T[u].mx=x;
 76     else {
 77         int M=(T[u].l+T[u].r)>>1;                            //3
 78         if(r<=M) change(u<<1,r,x);
 79         else change(u<<1|1,r,x);
 80         maintain(u);
 81     }
 82 }
 83 void Negate(int u,int L,int R) {
 84     pushdown(u);
 85     if(L<=T[u].l && T[u].r<=R) {//打标记 同时作用于当前结点
 86         T[u].f=1;
 87         int t; t=T[u].mn,T[u].mn=-T[u].mx,T[u].mx=-t;        //4
 88     }
 89     else {
 90         int M=(T[u].l+T[u].r)>>1;
 91         if(L<=M) Negate(u<<1,L,R);
 92         if(M<R) Negate(u<<1|1,L,R);
 93         maintain(u);
 94     }
 95 }
 96 int query(int u,int L,int R) {
 97     pushdown(u);
 98     if(L<=T[u].l && T[u].r<=R) return T[u].mx;
 99     else {
100         int M=(T[u].l+T[u].r)>>1;
101         int ans=-INF;
102         if(L<=M) ans=max(ans,query(u<<1,L,R));
103         if(M<R) ans=max(ans,query(u<<1|1,L,R));
104         return ans;
105     }
106 }
107
108 //树链剖分
109 void modify(int u,int v) {
110     while(top[u]!=top[v]) {
111         if(dep[top[u]]<dep[top[v]]) swap(u,v);
112         Negate(1,w[top[u]],w[u]);
113         u=fa[top[u]];
114     }
115     if(u==v) return ;
116     if(dep[u]>dep[v]) swap(u,v);
117     Negate(1,w[son[u]],w[v]);                                //5
118 }
119 int query(int u,int v) {
120     int mx=-INF;
121     while(top[u]!=top[v]) {
122         if(dep[top[u]]<dep[top[v]]) swap(u,v);
123         mx=max(mx,query(1,w[top[u]],w[u]));
124         u=fa[top[u]];
125     }
126     if(u==v) return mx;
127     if(dep[u]>dep[v]) swap(u,v);
128     mx=max(mx,query(1,w[son[u]],w[v]));
129     return mx;
130 }
131
132 void read(int& x) {
133     char c=getchar();
134     while(!isdigit(c)) c=getchar();
135     x=0;
136     while(isdigit(c))
137         x=x*10+c-‘0‘ , c=getchar();
138 }
139 int main() {
140     //freopen("in.in","r",stdin);
141     //freopen("out.out","w",stdout);
142     int T; read(T);
143     while(T--) {
144         read(n);
145         z=0; es.clear();
146         FOR(i,0,n) g[i].clear();
147         int u,v,c;
148         FOR(i,1,n-1) {
149             read(u),read(v),read(c);
150             d[i][0]=u,d[i][1]=v,d[i][2]=c;
151             adde(u,v,c),adde(v,u,c);
152         }
153         dfs1(1),dfs2(1,1);
154         build(1,1,z);
155         FOR(i,1,n-1) {
156             if(dep[d[i][1]]<dep[d[i][0]]) swap(d[i][0],d[i][1]);
157             change(1,w[d[i][1]],d[i][2]);
158         }
159          char s[10];
160         while(scanf("%s",s)==1 && s[0]!=‘D‘) {
161             read(u),read(v);
162             if(s[0]==‘C‘) change(1,w[d[u][1]],v);
163             else if(s[0]==‘N‘) modify(u,v);
164             else printf("%d\n",query(u,v));
165         }
166     }
167     return 0;
168 }
时间: 2024-10-13 04:29:56

poj 3237 Tree(树链剖分,线段树)的相关文章

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

【POJ3237】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 throughN − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions

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

【CF725G】Messages on a Tree 树链剖分+线段树

[CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息传输过程如下: 1.信息的发起者把信息上传给他父亲节点处的跳蚤,然后自身进入等待状态.3.跳蚤国王在收到信息时会将信息立刻下传到发来信息的那个儿子,跳蚤国王可以在同一时刻下传多份信息.4.上传:a把信息传给b.如果b正处于等待状态,则b会立刻将a发来的信息下传回去.如果同时有好多个信息传给b,则b会

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

[HDU3710] Battle Over Cities [树链剖分+线段树+并查集+kruskal+思维]

题面 一句话题意: 给定一张 N 个点, M 条边的无向连通图, 每条边上有边权 w . 求删去任意一个点后的最小生成树的边权之和. 思路 首先肯定要$kruskal$一下 考虑$MST$里面去掉一个点,得到一堆联通块,我们要做的就是用原图中剩下的边把这些联通块穿起来 考虑这个点$u$在$MST$上的位置,可以知道有两种边:一种是从$u$的任意一个儿子的子树连到$u$的子树外面的,一种是在$u$的两个儿子的子树之间连接的 第一种情况: 考虑边$(u,v)$,没有进入$MST$中,那么若它是某个节

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,

BZOJ2243 (树链剖分+线段树)

Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. 解题分析 树链剖分+线段树. 开一个记录类型,记录某一段区间的信息.l 表示区间最左侧的颜色 , r 表示区间最右侧的颜色 , sum 表示区间中颜色段数量. 合并时判断一下左区间的右端点和有区间的左端点的颜色是否一样. 树上合并时需要用两个变量ans1,ans2来存储.ans1表示x往上走时形成的链的信息,

bzoj4304 (树链剖分+线段树)

Problem T2 (bzoj4304 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 解题分析 练手题.树链剖分+线段树. 参考程序 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #incl

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要