【Live Archive】7148 - LRIP【2014上海区域现场赛L】【树分治+线段树】
来源:互联网 发布:淘宝onlyanna 罗晓颖 编辑:程序博客网 时间:2024/05/16 23:57
传送门:【Live Archive】7148 - LRIP
前言:
去年参加上海区域赛时,第一道看的这一题,当时花了5分钟时间看出这题的做法……然后花了5个小时都没有AC,把队友坑的不要不要的……
然后最近这道题终于在LA上挂出来了,怀着激动的心情,准备把它艹掉……然后终于写完了代码,却怎么都过不了(虽然中间发现有地方有错……)。
然后我就弃疗了,又回去看了看题目,感觉题意可以理解成“树上的有限制的最长上升子序列”(一开始认为是子串的,事实上题意确实是子串……),然后我就弃疗了……因为不会做子序列。
嗯……直到今天,学弟和我说xg过了这题,确实是子串……然后我整个人就蛋疼了,“卧槽难道真的是我算法还有哪里有错没发现??“
赶紧打开LA,顺便点进My Submissions一看,震惊了!卧槽曾经WA的代码竟然AC了……特么被LA给逗到了,我猜大概是数据传错了,然后rejudge了。
我说当时怎么死活AC不了= =,由于LA蛋疼的不存代码,于是今天只好重新敲了一次,不过运气不错,一遍AC。
题目分析:
很显然的树分治。
枚举重心分治,然后我们看一个重心u,枚举儿子v,找到v为起点的所有的上升子串以及下降子串,同时保证子串合法(即串尾和u的值差的绝对值不超过D)。
然后考虑我们枚举的是上升子串,考虑其中一个子串,其最大值为val,然后由于根的值为val_root,这样,我们就要找到之前存下来的值为D-(val-val_root)里面的长度最长的下降子串,这里我们可以用线段树维护。
对于下降子串同理。
枚举完后,我们就将子串的深度插入到对应的val上,供下一棵子树查询。
然后本题就……做完了。
#include <stdio.h>#include <string.h>#include <set>#include <map>#include <math.h>#include <vector>#include <algorithm>using namespace std ;typedef long long LL ;#define clr( a , x ) memset ( a , x , sizeof a )#define cpy( a , x ) memcpy ( a , x , sizeof a )#define clrs( a , x , size ) memset ( a , x , sizeof ( a[0] ) * ( size ) )#define cpys( a , x , size ) memcpy ( a , x , sizeof ( a[0] ) * ( size ) )#define ls ( o << 1 )#define rs ( o << 1 | 1 )#define lson ls , l , m#define rson rs , m + 1 , r#define mid ( ( l + r ) >> 1 )const int MAXN = 200005 ;const int MAXE = 200005 ;struct Edge { int v , n ; Edge () {} Edge ( int v , int n ) : v ( v ) , n ( n ) {}} ;Edge E[MAXE] ;int H[MAXN] , cntE ;int Q[MAXN] , head , tail ;int up[MAXN << 2] , down[MAXN << 2] ;int vis2[MAXN << 2] , Time ;int vis[MAXN] ;int siz[MAXN] ;int pre[MAXN] ;int val[MAXN] ;int dep[MAXN] ;int S1[MAXN] , top1 ;int S2[MAXN] , top2 ;int n , D ;int ans ;void init () { ans = 1 ; cntE = 0 ; clr ( vis , 0 ) ; clr ( H , -1 ) ;}void addedge ( int u , int v ) { E[cntE ] = Edge ( v , H[u] ) ; H[u] = cntE ++ ;}int get_root ( int s ) { head = tail = 0 ; Q[tail ++] = s ; pre[s] = 0 ; while ( head != tail ) { int u = Q[head ++] ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( vis[v] || v == pre[u] ) continue ; pre[v] = u ; Q[tail ++] = v ; } } int root_siz = tail , root = s ; while ( head ) { int u = Q[-- head] , cnt = 0 ; siz[u] = 1 ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( vis[v] || v == pre[u] ) continue ; siz[u] += siz[v] ; if ( cnt < siz[v] ) cnt = siz[v] ; } cnt = max ( cnt , tail - siz[u] ) ; if ( cnt < root_siz ) { root = u ; root_siz = cnt ; } } return root ;}void get_up ( int s , int root ) { top1 = 0 ; if ( val[s] < val[root] || val[s] - val[root] > D ) return ; head = tail = 0 ; Q[tail ++] = s ; pre[s] = root ; dep[s] = 1 ; while ( head != tail ) { int u = Q[head ++] ; S1[top1 ++] = u ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( vis[v] || v == pre[u] ) continue ; if ( val[v] < val[u] || val[v] - val[root] > D ) continue ; pre[v] = u ; dep[v] = dep[u] + 1 ; Q[tail ++] = v ; } }}void get_down ( int s , int root ) { top2 = 0 ; if ( val[s] > val[root] || val[root] - val[s] > D ) return ; head = tail = 0 ; Q[tail ++] = s ; pre[s] = root ; dep[s] = 1 ; while ( head != tail ) { int u = Q[head ++] ; S2[top2 ++] = u ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( vis[v] || v == pre[u] ) continue ; if ( val[v] > val[u] || val[root] - val[v] > D ) continue ; pre[v] = u ; dep[v] = dep[u] + 1 ; Q[tail ++] = v ; } }}void check ( int o ) { if ( vis2[o] != Time ) { vis2[o] = Time ; up[o] = down[o] = 0 ; }}void update ( int x , int v , int f , int o , int l , int r ) { if ( l == r ) { check ( o ) ; if ( !f ) up[o] = max ( up[o] , v ) ; else down[o] = max ( down[o] , v ) ; return ; } int m = mid ; if ( x <= m ) update ( x , v , f , lson ) ; else update ( x , v , f , rson ) ; check ( ls ) ; check ( rs ) ; vis2[o] = Time ; up[o] = max ( up[ls] , up[rs] ) ; down[o] = max ( down[ls] , down[rs] ) ;}int query ( int L , int R , int f , int o , int l , int r ) { if ( vis2[o] != Time ) return 0 ; if ( L <= l && r <= R ) return !f ? up[o] : down[o] ; int m = mid ; if ( R <= m ) return query ( L , R , f , lson ) ; if ( m < L ) return query ( L , R , f , rson ) ; return max ( query ( L , R , f , lson ) , query ( L , R , f , rson ) ) ;}void dfs ( int u ) { int root = get_root ( u ) ; vis[root] = 1 ; ++ Time ; for ( int i = H[root] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( vis[v] ) continue ; get_up ( v , root ) ; get_down ( v , root ) ; for ( int j = 0 ; j < top1 ; ++ j ) { int x = S1[j] ; ans = max ( ans , dep[x] + 1 + query ( 0 , D - ( val[x] - val[root] ) , 1 , 1 , 0 , D ) ) ; } for ( int j = 0 ; j < top2 ; ++ j ) { int x = S2[j] ; ans = max ( ans , dep[x] + 1 + query ( 0 , D - ( val[root] - val[x] ) , 0 , 1 , 0 , D ) ) ; } for ( int j = 0 ; j < top1 ; ++ j ) { int x = S1[j] ; update ( val[x] - val[root] , dep[x] , 0 , 1 , 0 , D ) ; } for ( int j = 0 ; j < top2 ; ++ j ) { int x = S2[j] ; update ( val[root] - val[x] , dep[x] , 1 , 1 , 0 , D ) ; } } for ( int i = H[root] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( vis[v] ) continue ; dfs ( v ) ; }}void solve () { int u , v ; init () ; scanf( "%d%d" , &n , &D ) ; for ( int i = 1 ; i <= n ; ++ i ) { scanf ( "%d" , &val[i] ) ; } for ( int i = 1 ; i < n ; ++ i ) { scanf ( "%d%d" , &u , &v ) ; addedge ( u , v ) ; addedge ( v , u ) ; } dfs ( 1 ) ; printf ( "%d\n" , ans ) ;}int main () { int T ; scanf ( "%d" , &T ) ; Time = 0 ; clr ( vis2 , 0 ) ; for ( int i = 1 ; i <= T ; ++ i ) { printf ( "Case #%d: " , i ) ; solve () ; } return 0 ;}
- 【Live Archive】7148 - LRIP【2014上海区域现场赛L】【树分治+线段树】
- UVALive 7148 LRIP(树分治+STL)
- ACM-ICPC Live Archive Regionals 2014 >> 重拾2014上海区域赛
- [点分治] LA 7148 LRIP
- 2014亚洲区域赛现场赛上海站(SET+贪心)
- UVa Live 7147 贪心(2014 上海区域赛)
- 树分治(hdu5016-2014西安现场赛)
- 2016亚洲区域赛现场赛china final L题
- 2015 上海网赛 HDU5469 树分治
- ACM-ICPC Live Archive 6139 - Interval Product (线段树-点更新)
- LA3938 线段树+分治
- Live Archive 3902 Network 树 贪心
- UVALive 7148 LRIP
- 2014 ACM/ICPC 上海区域赛小记
- 2014 上海区域赛I,J ,B
- 【线段树分治】[BZOJ4311]向量
- hdu1394 分治 or 线段树
- HDU6183 cdq分治+线段树
- 黑盒测试和白盒测试
- Andriod SDK和Loadrunner的HTTP协议测试环境搭建
- Notepad++搭配MinGW编译运行C/C++程序
- hdu 3037 Saving Beans 组合数取模模板题。。
- 用JAVA正则表达式 删除字符串的特定子串
- 【Live Archive】7148 - LRIP【2014上海区域现场赛L】【树分治+线段树】
- windows内存管理的机制以及优缺点
- try块和异常处理
- OpenCV学习笔记(4):膨胀,腐蚀,开闭操作(argc,argv)
- 01背包经典
- 使用memcache存储session数据
- 黑马程序员IOS基础---C语言学习之typedef
- DS之链表实现就地逆置
- memcache的另一种扩展libmemcached的安装