poj 3237 Tree(树链剖分,线段树)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj 3237 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
【思路】
树链剖分,线段树。
又练了一边线段树<_<,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 }
以上是关于poj 3237 Tree(树链剖分,线段树)的主要内容,如果未能解决你的问题,请参考以下文章
POJ3237-Tree (树链剖分,线段树区间更新+点更新+区间查询)