题目
题解&思路:
自己的思路:
没有时间看了,我怎么这么菜呀
正解: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)主席树...