bzoj1036 count 树链剖分或LCT

这道题很久以前用树链剖分写的,最近在学LCT ,就用LCT再写了一遍,也有一些收获。

因为这道题点权可以是负数,所以在update时就要注意一下,因为平时我的0节点表示空,它的点权为0,这样可以处理点权为非负求最大值和求和的情况(即不用特判某个点是否有左右儿子,直接更新就行了),但这道题就不行(求和要求它为0,求最大值要求它为-oo)。所以就必须特判~~~~

综上:若0号节点存在一个不可能成为答案(在求最大值时是-oo,求最小值时是+oo)或对答案没有贡献的值(在求和时是0)时,初始化时将0节点的权值设为该值,更新时就可以不用特判某个点是否为0。否则引用左右儿子值时就必须特判某个节点是否有左右儿子。

LCT用的时间大概是树链剖分的两倍。

树链剖分:

  1 /**************************************************************
  2     Problem: 1036
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:2880 ms
  7     Memory:5116 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11 #include <vector>
 12 #define lson rt<<1
 13 #define rson rt<<1|1
 14 #define inf 300000000
 15 #define maxn 30001
 16 using namespace std;
 17
 18 int n;
 19 vector<int> g[maxn];
 20 int wght[maxn], siz[maxn], son[maxn], pre[maxn], dep[maxn], top[maxn], vid[maxn], vcnt;
 21 int smax[maxn<<2], ssum[maxn<<2];
 22
 23 void up_sum( int pos, int v, int rt, int l, int r ) {
 24     if( l==r ) {
 25         ssum[rt] = v;
 26         return;
 27     }
 28     int mid=(l+r)>>1;
 29     if( mid>=pos ) up_sum( pos, v, lson, l, mid );
 30     else up_sum( pos, v, rson, mid+1, r );
 31     ssum[rt] = ssum[lson] + ssum[rson];
 32 }
 33 void up_max( int pos, int v, int rt, int l, int r ) {
 34     if( l==r ) {
 35         smax[rt] = v;
 36         return;
 37     }
 38     int mid=(l+r)>>1;
 39     if( mid>=pos ) up_max( pos, v, lson, l, mid );
 40     else up_max( pos, v, rson, mid+1, r );
 41     smax[rt] = max( smax[lson], smax[rson] );
 42 }
 43 int qu_sum( int L, int R, int rt, int l, int r ) {
 44     if( L<=l && r<=R ) return ssum[rt];
 45     int mid=(l+r)>>1, re=0;
 46     if( mid>=L ) re+=qu_sum(L,R,lson,l,mid);
 47     if( mid+1<=R ) re+=qu_sum(L,R,rson,mid+1,r);
 48     return re;
 49 }
 50 int qu_max( int L, int R, int rt, int l, int r ) {
 51     if( L<=l && r<=R ) return smax[rt];
 52     int mid=(l+r)>>1, re=-inf;
 53     if( mid>=L ) re = qu_max( L,R,lson,l,mid);
 54     if( mid+1<=R ) re = max( re, qu_max( L,R,rson,mid+1,r ) );
 55     return re;
 56 }
 57 void dfs1( int u ) {
 58     siz[u] = 1, son[u] = 0;
 59     for( int t=0; t<(int)g[u].size(); t++ ) {
 60         int v=g[u][t];
 61         if( v==pre[u] ) continue;
 62         pre[v] = u;
 63         dep[v] = dep[u]+1;
 64         dfs1(v);
 65         siz[u] += siz[v];
 66         son[u] = siz[v]>siz[son[u]] ? v : son[u];
 67     }
 68 }
 69 void dfs2( int u, int tp ) {
 70     vid[u] = ++vcnt, top[u] = tp;
 71     if( son[u] ) dfs2(son[u],tp);
 72     for( int t=0; t<(int)g[u].size(); t++ ) {
 73         int v=g[u][t];
 74         if( v==pre[u] || v==son[u] ) continue;
 75         dfs2(v,v);
 76     }
 77 }
 78 void build() {
 79     pre[1] = 1, dep[1] = 1;
 80     dfs1(1);
 81     vcnt = 0;
 82     dfs2(1,1);
 83     for( int i=1; i<=n; i++ ) {
 84         up_sum( vid[i], wght[i], 1, 1, vcnt );
 85         up_max( vid[i], wght[i], 1, 1, vcnt );
 86     }
 87 }
 88 void update( int v, int val ) {
 89     up_sum( vid[v], val, 1, 1, vcnt );
 90     up_max( vid[v], val, 1, 1, vcnt );
 91 }
 92 int query_sum( int u, int v ) {
 93     int r=0;
 94     while( top[u]!=top[v] ) {
 95         if( dep[top[u]]<dep[top[v]] ) swap(u,v);
 96         r += qu_sum( vid[top[u]], vid[u], 1, 1, vcnt );
 97         u = pre[top[u]];
 98     }
 99     if( u==v ) return r+qu_sum(vid[u],vid[v],1,1,vcnt);
100     if( dep[u]<dep[v] ) swap(u,v);
101     r += qu_sum( vid[v], vid[u], 1, 1, vcnt );
102     return r;
103 }
104 int query_max( int u, int v ) {
105     int r=-inf;
106     while( top[u]!=top[v] ) {
107         if( dep[top[u]]<dep[top[v]] ) swap(u,v);
108         r = max( r, qu_max( vid[top[u]], vid[u], 1, 1, vcnt ) );
109         u = pre[top[u]];
110     }
111     if( u==v ) return max( r, qu_max( vid[u], vid[v], 1, 1, vcnt ) );
112     if( dep[u]<dep[v] ) swap(u,v);
113     r = max( r, qu_max( vid[v], vid[u], 1, 1, vcnt ) );
114     return r;
115 }
116 void answer() {
117     int q, a, b;
118     scanf( "%d", &q );
119     while(q--) {
120         char dir[10];
121         scanf( "%s%d%d", dir, &a, &b );
122         if( dir[0]==‘C‘ )
123             update(a,b);
124         else if( dir[1]==‘S‘ )
125             printf( "%d\n", query_sum(a,b) );
126         else
127             printf( "%d\n", query_max(a,b) );
128     }
129 }
130 void input() {
131     scanf( "%d", &n );
132     for( int i=1,u,v; i<n; i++ ) {
133         scanf( "%d%d", &u, &v );
134         g[u].push_back(v);
135         g[v].push_back(u);
136     }
137     for( int i=1; i<=n; i++ )
138         scanf( "%d", wght+i );
139 }
140 int main() {
141     input();
142     build();
143     answer();
144 }

LCT:

  1 /**************************************************************
  2     Problem: 1036
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:5816 ms
  7     Memory:2932 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11 #include <iostream>
 12 #define maxn 30010
 13 #define oo 0x3f3f3f3f
 14 using namespace std;
 15
 16 namespace L {
 17     int pnt[maxn], pre[maxn], son[maxn][2], val[maxn], mxv[maxn], sum[maxn], rtg[maxn];
 18
 19     void update( int u ) {
 20         mxv[u] = sum[u] = val[u];
 21         int ls = son[u][0], rs = son[u][1];
 22         if(ls) {
 23             mxv[u] = max( mxv[u], mxv[ls] );
 24             sum[u] += sum[ls];
 25         }
 26         if(rs) {
 27             mxv[u] = max( mxv[u], mxv[rs] );
 28             sum[u] += sum[rs];
 29         }
 30     }
 31     void rotate( int u, int d ) {
 32         int p = pre[u];
 33         int s = son[u][!d];
 34         int ss = son[s][d];
 35         son[u][!d] = ss;
 36         son[s][d] = u;
 37         if( p ) son[p][ u==son[p][1] ] = s;
 38         else pnt[s] = pnt[u];
 39         pre[u] = s;
 40         pre[ss] = u;
 41         pre[s] = p;
 42         update( u );
 43         update( s );
 44     }
 45     void pushdown( int u ) {
 46         if( rtg[u] ) {
 47             int &ls = son[u][0], &rs = son[u][1];
 48             swap( ls, rs );
 49             rtg[ls] ^= 1;
 50             rtg[rs] ^= 1;
 51             rtg[u] = 0;
 52         }
 53     }
 54     void big_push( int u ) {
 55         if( pre[u] ) big_push(pre[u]);
 56         pushdown( u );
 57     }
 58     void splay( int u, int top=0 ) {
 59         big_push( u );
 60         while( pre[u]!=top ) {
 61             int p = pre[u];
 62             int nl = u==son[p][0];
 63             if( pre[p]==top ) {
 64                 rotate( p, nl );
 65             } else {
 66                 int pp = pre[p];
 67                 int pl = p==son[pp][0];
 68                 if( nl==pl ) {
 69                     rotate( pp, pl );
 70                     rotate( p, nl );
 71                 } else {
 72                     rotate( p, nl );
 73                     rotate( pp, pl );
 74                 }
 75             }
 76         }
 77     }
 78     void access( int nd ) {
 79         int u = nd;
 80         int v = 0;
 81         while( u ) {
 82             splay( u );
 83             int s = son[u][1];
 84             pre[s] = 0;
 85             pnt[s] = u;
 86             pre[v] = u;
 87             son[u][1] = v;
 88             update(u);
 89             v = u;
 90             u = pnt[u];
 91         }
 92         splay( nd );
 93     }
 94     int findroot( int u ) {
 95         while( pre[u] ) u = pre[u];
 96         while( pnt[u] ) {
 97             u = pnt[u];
 98             while( pre[u] ) u = pre[u];
 99         }
100         return u;
101     }
102     void makeroot( int u ) {
103         access( u );
104         rtg[u] ^= 1;
105     }
106     void link( int u, int v ) {
107         makeroot( u );
108         makeroot( v );
109         pnt[u] = v;
110     }
111     void up_val( int u, int w ) {
112         splay( u );
113         val[u] = w;
114         update( u );
115     }
116     int qu_max( int u, int v ) {
117         makeroot( u );
118         access( v );
119         if( son[v][0] ) return max( val[v], mxv[son[v][0]] );
120         else return val[v];
121     }
122     int qu_sum( int u, int v ) {
123         makeroot( u );
124         access( v );
125         if( son[v][0] ) return val[v] + sum[son[v][0]];
126         else return val[v];
127     }
128 };
129
130 int n, q;
131
132 int main() {
133     scanf( "%d", &n );
134     for( int i=2,u,v; i<=n; i++ ) {
135         scanf( "%d%d", &u, &v );
136         L::link(u,v);
137     }
138     for( int i=1,w; i<=n; i++ ) {
139         scanf( "%d", &w );
140         L::up_val(i,w);
141     }
142     scanf( "%d", &q );
143     while( q-- ) {
144         char ch[20];
145         int u, v, w;
146         scanf( "%s", ch );
147         if( ch[0]==‘C‘ ) {
148             scanf( "%d%d", &u, &w );
149             L::up_val( u, w );
150         } else if( ch[1]==‘M‘ ) {
151             scanf( "%d%d", &u, &v );
152             printf( "%d\n", L::qu_max( u, v ) );
153         } else {
154             scanf( "%d%d", &u, &v );
155             printf( "%d\n", L::qu_sum( u, v ) );
156         }
157     }
158 }
159
160 

时间: 2024-10-13 11:08:20

bzoj1036 count 树链剖分或LCT的相关文章

HYSBZ - 1036 树的统计Count 树链剖分 求和+最大值

好水0.0 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #include<string> #define eps 1e-12 #de

【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分

[BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 Input 输入的第一行为一个整数n,表示节点的个数.接下来n

[BZOJ1036/ZJOI2008]树的统计(Count)-树链剖分

Problem 树的统计 题目大意 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 So Lazy No Solution 裸的树链剖分,题解一搜一大把.就连这个都炸了几次.我太菜了... AC

bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

[ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 Input 输入的第一行为一个整数n,表示节点的个数.接下来n – 1行,每行

【BZOJ1036】【ZJOI2008】树的统计Count 树链剖分裸题

题解:裸的,没什么好说的. 树链剖分不会的先理解一下重链轻链,然后直接扒我代码理解就行了. 贴代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 30100 #define inf 0x3f3f3f3f using namespace std; struct KSD { int u,v,next; }e[N<<1];

BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14302  Solved: 5779[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

bzoj 1036 [ZJOI2008]树的统计Count 树链剖分模板

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 18615  Solved: 7598[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时... 代码如下: 1 //树链剖分 点权修改 修改单节点 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdio> 6 using namespa

bzoj 1036 树的统计Count (树链剖分+线段树)

题目大意:给你一棵树,每个点都有点权 有3种操作,修改某节点的权值,求树链上节点的权值的最大值,求树链上节点的权值和 树剖裸题,搜一个树链剖分序,用线段树维护一下即可,总时间 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <queue> 5 #define inf 0x3f3f3f3f 6 #define ll long long 7 #define N