【BJOI2014】大融合

题目

 

题解&&思路:

自己的思路:

首先这道题可以发现离线是可做的,然后因为自己太菜,没有发现加边更好做,于是一直在考虑删边

删边有点烦,首先对于删去一条边后它及它的祖先的siz都会影响,那么可以使用树剖,每个点记一下siz即可

但是还没完,这样做如果删边时会影响到连通性,因为是离线则一个点的最终祖先(这里表示从当前点一直往上直到不可走为止所到的点)是会变的,sb的我发现这个东西也可以用树剖维护一下,就变得可做了

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int MAXN = 1e5 + 3;
int id[MAXN] , n , m , head[MAXN] , cnt = 1 , inde , top[MAXN] , siz[MAXN] , fa[MAXN];
int dep[MAXN] , son[MAXN] , dfn[MAXN] , zfa[MAXN];
struct node{
    int op , x , y;
}ques[MAXN];
struct edge{
    int to , nex;
}G[MAXN<<1];
ll ans[MAXN];
char o[3];
void add_edge( int x , int y ){
    G[cnt].to = y , G[cnt].nex = head[x];
    head[x] = cnt ++;
}
void dfs( int x , int f , int zx ){
    zfa[x] = zx;
    siz[x] = 1;
    for( int i = head[x] ; i ; i = G[i].nex ){
        int v = G[i].to;
        if( v == f ) continue;
        fa[v] = x;
        dep[v] = dep[x] + 1;
        dfs( v , x , zx );
        siz[x] += siz[v];
        if( !son[x] || siz[son[x]] < siz[v] ) son[x] = v;
    }
}
void dfs1( int x , int f ){
    top[x] = f;
    id[x] = ++inde;dfn[inde] = x;
    if( !son[x] ) return ;
    dfs1( son[x] , f );
    for( int i = head[x] ; i ; i = G[i].nex ){
        int v = G[i].to;
        if(fa[x] == v || son[x] == v ) continue;
        dfs1( v , v );
    }
}
struct tree{
    int l , r , lazy1 , zx;
    ll sum, lazy;
}tre[MAXN<<2];
int min_( int x , int y ){
    if( x == inf ) return y;
    if( y == inf ) return x;
    if( dep[x] > dep[y] ) return x;
    return y;
}
void build( int i , int l , int r ){
    tre[i].l = l , tre[i].r = r , tre[i].lazy = 0 , tre[i].sum = 0 , tre[i].lazy1 = inf;
    if( l == r ){
        tre[i].sum = siz[dfn[l]];tre[i].zx = zfa[dfn[l]];
        return ;
    }
    int mid = l + r >> 1;
    build( i << 1 , l , mid );
    build( i << 1 | 1 , mid + 1, r );
}
void pushdown( int i ){
    if( tre[i].lazy ){
        tre[i<<1].sum -= tre[i].lazy , tre[i<<1|1].sum -= tre[i].lazy;
        tre[i<<1].lazy += tre[i].lazy , tre[i<<1|1].lazy += tre[i].lazy;
        tre[i].lazy = 0;
    }
    if( tre[i].lazy1 != inf ){
        tre[i<<1].zx = min_( tre[i<<1].zx , tre[i].lazy1 ) , tre[i<<1|1].zx = min_( tre[i<<1|1].zx , tre[i].lazy1 );
        tre[i<<1].lazy1 = min_( tre[i<<1].lazy1 , tre[i].lazy1 ) , tre[i<<1|1].lazy1 = min_( tre[i<<1|1].lazy1 , tre[i].lazy1 );
        tre[i].lazy1 = inf;
    }
}
void pushup( int i ){
    tre[i].sum = tre[i<<1].sum + tre[i<<1|1].sum;
    tre[i].zx = min_( tre[i<<1].zx , tre[i<<1|1].zx );
}
void modify( int i , int l , int r , int delta ){
    if( tre[i].l > r || tre[i].r < l ) return ;
    if( tre[i].l >= l && tre[i].r <= r ){
        tre[i].sum -= delta;
        tre[i].lazy += delta;
        return ;
    }
    pushdown( i );
    modify( i << 1 , l , r , delta );
    modify( i << 1 | 1, l , r , delta );
    pushup( i );
}
void modify1( int i , int l, int r , int p ){
    if( tre[i].l > r || tre[i].r < l ) return ;
    if( tre[i].l >= l && tre[i].r <= r ){
        tre[i].zx = min_( tre[i].zx , p );
        tre[i].lazy1 = min_( tre[i].lazy1 , p );
        return ;
    }
    pushdown( i );
    modify1( i << 1 , l , r , p );
    modify1( i << 1 | 1, l , r , p );
    pushup( i );
}
ll query( int i , int l , int r ){
    if( tre[i].l > r || tre[i].r < l ) return 0;
    if( tre[i].l >= l && tre[i].r <= r ){
        return tre[i].sum;
    }
    pushdown( i );
    ll su = query( i << 1 , l , r );
    su += query( i << 1 | 1, l , r );
    pushup( i );
    return su;
}
int query1( int i , int l , int r ){
    if( tre[i].l > r || tre[i].r < l ) return inf;
    if( tre[i].l >= l && tre[i].r <= r ){
        return tre[i].zx;
    }
    pushdown( i );
    int su = query1( i << 1 , l , r );
    su = min_( su , query1( i << 1 | 1, l , r ) );
    pushup( i );
    return su;
}
int main(){
   // freopen( "path.in" , "r" , stdin );
    //freopen( "path.out" , "w" , stdout );
    scanf( "%d%d" , &n , &m );
    for( int i = 1 ;i <= m; i ++ ){
        scanf( "%s" , o );
        if( o[0] == 'A' ){
            ques[i].op = 1;
            scanf( "%d%d" , &ques[i].x , &ques[i].y );
            add_edge( ques[i].x , ques[i].y );
            add_edge( ques[i].y , ques[i].x );
        }
        else{
            ques[i].op = 0;
            scanf( "%d%d" , &ques[i].x , &ques[i].y );
        }
    }
    for( int i = 1 ; i <= n ; i ++ ){
        if( !fa[i] ){
            dep[i] = 1;
            dfs( i , 0 , i );
        }
    }
    for( int i = 1 ; i <= n ; i ++ ){
        if( !fa[i] ){
            dfs1( i , i );
        }
    }
    build( 1 , 1 , n );
    for( int i = m ; i >= 1 ; i -- ){
        if( ques[i].op ){
            int x = ques[i].x , y = ques[i].y;
            if( dep[x] < dep[y] ) swap( x , y );
            int p2 = x , p = query( 1 , id[x] , id[x] ) , p1 = query1( 1 , id[x] , id[x] );
            x = y;
            while( top[x] != top[p1] ){
                modify( 1 , id[top[x]] , id[x] , p );
                x = fa[top[x]];
            }
            modify( 1 , id[p1] , id[x] , p );
            modify1( 1 , id[p2] , id[p2] + siz[p2] - 1 , p2 );
        }
        else{
            int x = ques[i].x , y = ques[i].y;
            if( dep[x] < dep[y] ) swap( x , y );
            y = query1( 1 , id[x] , id[x] );
            int p = query( 1 , id[y] , id[y] ) ;
            int p1 = query( 1 , id[x] , id[x] );
            ans[i] = 1ll *( p - p1 ) * p1;
        }
    }
    for( int i = 1 ; i <= m ; i ++ ){
        if( !ques[i].op ){
            printf( "%lld\n" , ans[i] );
        }
    }
    return 0;
}

代码很长,因为自己太菜了思路太复杂

本身思路是对的,然而自己从没有把树剖一次写对过,这次又挂了一个点,还是同样的modify:

while( top[x] != top[p1] ){
                modify( 1 , id[top[x]] , id[x] , p );
                x = fa[top[x]];
            }
            modify( 1 , id[top[p1]] , id[x] , p );
            modify1( 1 , id[p2] , id[p2] + siz[p2] - 1 , p2 );

 

理解起来就是我把modify范围写挂了。。。

之前写错while,这次写错modify,要加强练习啊

其它解:

还是考虑使用树剖,这时按顺序加边,可以使用一个并查集维护连通性,而它的最终祖先是可以通过并查集维护的,就会变得TM好写得多

为了加强自己练习,就把这道题用这种方法再重构一遍:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 1e5 + 3;
int n , m , top[MAXN] , siz[MAXN] , dep[MAXN] , fa[MAXN] , fa1[MAXN] , id[MAXN] , zson[MAXN];
vector<int>G[MAXN];
struct tree{
    int l , r;
    ll lazy , sum;
}tre[MAXN<<2];
struct node{
    int op , x , y;
}q[MAXN];
void dfs( int x , int f ){
    siz[x] = 1;
    for( int i =0 ; i < G[x].size() ; i ++ ){
        int v = G[x][i];
        if( v == f ) continue;
        dep[v] = dep[x] + 1;
        fa[v] = x;
        dfs( v , x );
        siz[x] += siz[v];
        if( !zson[x] || siz[zson[x]] < siz[v] ) zson[x] = v;
    }
}
int inde;
void dfs1( int x , int f ){
    top[x] = f;
    id[x] = ++inde;
    if( !zson[x] ) return ;
    dfs1( zson[x] , f );
    for( int i = 0 ; i < G[x].size() ; i ++ ){
        int v = G[x][i];
        if( v == fa[x] || v==zson[x] ) continue;
        dfs1( v , v );
    }
}
int findSet( int x ){
    if( x != fa1[x] ) fa1[x] = findSet( fa1[x] ) ;
    return fa1[x];
}
void unionSet( int x , int y ){
    int u = findSet( x ) , v = findSet( y );
    if( u == v ) return;
    if( dep[u] < dep[v] ) fa1[v] = u;
    else fa1[u] = v;
}
void pushdown( int i ){
    if( tre[i].lazy ){
        tre[i<<1].lazy += tre[i].lazy , tre[i<<1|1].lazy += tre[i].lazy;
        tre[i<<1].sum += tre[i].lazy , tre[i<<1|1].sum += tre[i].lazy;
        tre[i].lazy = 0;
    }
}
void build( int i , int l , int r ){
    tre[i].l = l , tre[i].r = r , tre[i].lazy = tre[i].sum = 0;
    if( l == r){tre[i].sum = 1;return ;}
    int mid = l + r >> 1;
    build( i << 1 , l ,mid);
    build( i << 1 | 1,  mid + 1 ,r );
}
void modify( int i , int l , int r , int delta ){
    if( tre[i].l > r || tre[i].r < l ) return ;
    if( tre[i].l >= l && tre[i].r <= r ){
        tre[i].sum += delta;
        tre[i].lazy += delta;
        return ;
    }
    pushdown( i );
    modify( i << 1 , l , r, delta );
    modify( i << 1 | 1 , l , r , delta );
}
int query( int i , int l , int r ){
    if( tre[i].l > r || tre[i].r < l ) return 0;
    if( tre[i].l >= l && tre[i].r <= r ){
        return tre[i].sum;
    }
    pushdown( i );
    int an = query( i << 1 , l , r);
    an += query( i << 1 | 1 , l , r);
    return an;
}
int main(){
    scanf( "%d%d" , &n , &m );
    for( int i = 1 ; i <= m ; i ++ ){
        char o[3];
        scanf( "%s" , o );
        if( o[0] == 'A' )
            q[i].op = 1;
        else q[i].op = 0;
        scanf( "%d%d" , &q[i].x , &q[i].y );
        if( q[i].op ){
            G[q[i].x].push_back( q[i].y );
            G[q[i].y].push_back( q[i].x );
        }
    }
    for( int i = 1 ; i <= n ; i ++ ) fa1[i] = i;
    for( int i = 1 ;i <= n ; i ++ ){
        if( !fa[i]) {
            dep[i] = 1;
            dfs( i , 0 );
        }
    }
    for( int i = 1 ; i <= n ; i ++) {
        if( !fa[i] ){
            dfs1( i , i );
        }
    }
    build( 1, 1 , n );
    for( int i = 1 ;i <= m ; i++ ){
        if( q[i].op ){
            int x = q[i].x , y = q[i].y;
            if( dep[x] > dep[y] ) swap( x , y );
            unionSet( x , y );
            int la = findSet( x ) , q = query( 1 , id[y] , id[y] );
            while( top[x] != top[la] ){
                modify( 1 , id[top[x]] , id[x] , q );
                x = fa[top[x]];
            }
            modify( 1 , id[la] , id[x] , q );
        }
        else{
            int x = q[i].x , y = q[i].y;
            if( dep[x] > dep[y] ) swap( x , y );
            int la = findSet( x ) , p = query( 1 , id[la] , id[la] );
            int p1 = query( 1 , id[y] , id[y] );
            printf( "%lld\n" , 1ll * ( p - p1 ) * p1 );
        }
    }
}

花了25min rush掉了,代码能力还需加强,还不够快 

正解:

LCT

再见

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值