意念的交流

12 篇文章 0 订阅
5 篇文章 0 订阅

题目

 

 题解&思路:

自己的思路:

没有时间看了,我怎么这么菜呀

正解:kruskal重构树 + 启发式合并

首先根据这个性质可以发现这就是kruskal重构树嘛(可是我并没有学过),然后考虑每个虚点的点权的贡献,因为这是一个二叉树,所以考虑进行启发式合并来优化,即在两个儿子中找儿子siz更小的考虑对另一个子树贡献,现在对于一个点i,假设其左子树siz大于右子树siz,那么对于右子树的一个点,与它贡献的点的值是i的点权的话,那么这个点的dfs序(在重构树上)就必须在左子树之内,且它的c满足在一个范围中,这样就转换成了一些偏序问题,考虑维护,不难发现是用树状数组二维数点即可

这里还要特判L=0的情况,因为L=0时算矩形会算重,倒不如直接用左子树的点个数*右子树点个数*当前点权值即可

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 2e5 + 3;
const int MAXM = 5e5 + 3;
const int M = 1e7 + 3;
inline char GetChar(){
    static char buf[10001],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,10001,stdin),p1==p2)?EOF:*p1++;
}
inline void Read(int &n){
    short f=1;
    long long x=0;
    char c=GetChar();
    while(isdigit(c)==false){
        if(c=='-'){
            f=-1;
		}
        c=GetChar();
    }
    while(isdigit(c)==true){
    	x=((x<<3)+(x<<1)+(c^48));
        c=GetChar();
    }
    n=x*f;
}
int n , m , L , fa[MAXN<<1] , c[MAXN<<1] , in_[MAXN<<1] , out_[MAXN<<1] , ncnt , k , dfn[MAXN] , ind;
int son[MAXN<<1][2];
struct node{
    int x , y , l;
    friend bool operator < ( node a , node b ){
        return a.l < b.l;
    }
}E[MAXM];
ll ans = 0;
struct node1{
    int l , r , num , x , c;
    friend bool operator < ( node1 a,  node1 b ){
        if( a.x ^ b.x ) return a.x < b.x;
        return a.num < b.num;
    }
}a[M];
int cnts , fd[MAXN];
int findSet( int x ){
    if( x != fa[x] ) fa[x] = findSet( fa[x] );
    return fa[x];
}
void unionSet( int x , int y , int l ){
	int u = findSet( x ) , v = findSet( y );
	if( u == v ) return ;
	ncnt ++;
    fa[u] = fa[v] = ncnt;
    c[ncnt] = l;
    k ++;
    son[ncnt][0] = u , son[ncnt][1] = v;
}
struct node2{
    int num , x;
    friend bool operator < ( node2 a,  node2 b ){
        return a.x < b.x;
    }
}b[MAXN*3];
int mp[MAXN*3] , q1;
void dfs( int x, int f ){
    in_[x] = ind + 1;
    if( !son[x][0] || x <= n ){
        dfn[x] = ++ind;
        fd[ind] = x;
        out_[x] = ind;
        return ;
    }
    for( int i = 0 ; i <= 1 ; i ++ ){
        int v = son[x][i];
        dfs( v , x );
    }
    if( !L ){
        ll s1 = out_[son[x][0]] - in_[son[x][0]] + 1;
        ll s2 = out_[son[x][1]] - in_[son[x][1]] + 1;
        ans = ans + s2 * s1 * c[x];
    }
    else{
        int u = son[x][0] , v = son[x][1];
        if( out_[son[x][0]] - in_[son[x][0]] + 1 > out_[son[x][1]] - in_[son[x][1]] + 1 ) swap( u , v );
    	for( int i = in_[u] ; i <= out_[u] ; i ++ ){
            int vv = fd[i];
            if( mp[vv+n] ){
                a[++cnts].x = in_[v] , a[cnts].l = 1;a[cnts].c = c[x];
                a[cnts].r = mp[vv+n];a[cnts].num = 0;
                a[++cnts].x = out_[v] , a[cnts].l = 1;a[cnts].c = c[x];
                a[cnts].r = mp[vv+n];a[cnts].num = 2;
            }
            if( mp[vv+2*n] ){
                a[++cnts].x = in_[v] , a[cnts].l = mp[vv+2*n];a[cnts].c = c[x];
                a[cnts].r = q1;a[cnts].num = 0;
                a[++cnts].x = out_[v] , a[cnts].l = mp[vv+2*n];a[cnts].c = c[x];
                a[cnts].r = q1;a[cnts].num = 2;
            }
        }
    }
    out_[x] = ind;
}
int tre[MAXN*3];
void modify( int x , int delta ){
    for( ; x <= q1 ; x += ( x & -x ) )
        tre[x] ++;
}
int query( int x ){
    int sum = 0;
    for( ; x ; x -= ( x & -x ) )
        sum += tre[x];
    return sum;
}
int main(){
	//freopen( "commu.in" , "r" , stdin );
	//freopen( "commu.out" , "w" , stdout );
    Read( n );Read( m );Read( L );
    int q = 0;
    for( int i = 1 ; i <= n ; i ++ ){
        Read( c[i] );
        b[++q].num = i , b[q].x = c[i];b[++q].num = i + n , b[q].x = c[i] - L;b[++q].num = i + 2 * n , b[q].x = c[i] + L;
    }
    sort( b + 1 , b + q + 1 );
    q1 = 0;
    for( int i = 1 ; i <= q ; i ++ ){
        if( b[i].x < 0 ) continue;
        if( b[i].x != b[i-1].x || i == 1 )
            mp[b[i].num] = ++q1;
        else
            mp[b[i].num] = q1;
    }
    for( int i = 1 ; i <= m ; i ++ ){
        int x , y , z;Read(x);Read( y );Read( z);
        E[i].x = x , E[i].y = y , E[i].l = z;
    }
    ncnt = n;
    sort( E + 1 , E + m + 1 );
    for( int i = 1 ; i <= 2 * n ; i ++ ) fa[i] = i;
    k = 0;
    for( int i = 1 ; i<= m ;i ++ ){
        int x = E[i].x , y = E[i].y , l = E[i].l;
       // printf( "%d %d\n" , x , y);
        unionSet( x , y , l );
        if( k == n - 1 ) break;
    }
    dfs( ncnt , 0 );
    //return 0;
    //return 0 ;
	if( L ){
        for( int i = 1 ; i <= n ; i ++ ){
            a[++cnts].l = mp[i] , a[cnts].num = 1 , a[cnts].x = dfn[i];
        }
        sort( a + 1 , a + cnts + 1 );
        for( int i = 1 ; i <= cnts ; i ++ ){
            if( a[i].num == 1 )
                modify( a[i].l , 1 );
            else if( a[i].num == 0 ){
                int s1 = query( a[i].l - 1 ) , s2 = query( a[i].r );
                s2 -= s1;
                ans -= 1ll * s2 * a[i].c;
            }
            else{
                int s1 = query( a[i].l - 1 ) , s2 = query( a[i].r );
                s2 -= s1;
                ans += 1ll * s2 * a[i].c;
            }
        }
    }
    printf( "%lld" , ans );
    return 0;
}

至于另一种方法可以用线段树合并,我不会。。。

总结

现在已知的解决偏序关系问题的方法:

1.CDQ分治

2.数据结构:

(1)可以使用单调队列,差分

  (2)二维树状数组区间数点

  (3)主席树...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值