传送门:【codeforces】2014-2015ACM-ICPC CERC 14 Problem J: Pork barrel
题目分析:pushup内写错了一直没发现。。。把maxidx写成idx然后查了一下午没查出来,到晚饭后才发现。。然后再纠正了数组大小,终于AC了。。。写了我一下午,就因为这么一个小错误T T
今天是平安夜,祝大家平安夜快乐!
这题是要维护一个最小生成树的构造过程。
首先,我们假设这题可以离线!
我们先将边从大到小排序,然后依次连接两点,如果某一次枚举的边的两点已经在一条链上,那么我们删除这个链上权值最大的边,然后添加这次枚举的边,这样我们既保证了连通块的数量不会增加,同时维护这么多连通块的花费也不会增加。然后我们用到了第i小的边,那么在区间中第i个位置加上这条边的权值,删除的时候就减小。
此时我们注意,当存在询问【L,R】时,如果当前枚举的边是大于等于L的最小的边,那么这时我们决定处理这个询问【L,R】。此时用到的边的最小值就是区间内【L,R】的权值和!这个我们可以用树状数组维护,且由于【1,L-1】都还没被插入,所以其实就是【1,R】内的权值和。大于R的如果是被删除的那么本来就不需要,如果是树边则只能不是用它而增加连通块个数(因为被限制只能使用权值【L,R】内的边),小于等于R的无论怎么和权值稍大且同样小于等于R的被删除的边交换,连通块个数也不会减少,因为即使没有小于等于R的限制这些边一样要删除(可能我这样描述也不太正确,抱歉T T)。进行操作前还需要将询问按照左端点从大到小排个序。
现在问题要求强制在线,那么要么用可持久化树状数组(不知道有没有,反正我不会),要么可以用主席树(可持久化线段树)。这里我是选择主席树了。
除了用主席树保存历史记录,其他都和离线的差不多。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define lson l , m
#define rson m + 1 , r
#define mid ( ( l + r ) >> 1 )
const int MAXN = 1005 ;
const int MAXE = 100005 ;
const int INF = 0x3f3f3f3f ;
namespace PST {
struct Node {
Node* c[2] ;
int sum ;
inline void pushup () {
sum = c[0]->sum + c[1]->sum ;
}
} ;
Node pool[MAXE * 40] ;
Node* node[MAXE] ;
Node* cur ;
inline void init () {
cur = pool ;
}
inline void build ( Node* &o , int l , int r ) {
o = cur ++ ;
o->sum = 0 ;
if ( l == r ) return ;
int m = mid ;
build ( o->c[0] , lson ) ;
build ( o->c[1] , rson ) ;
}
inline void insert ( Node* old , Node* &now , int x , int v , int l , int r ) {
now = cur ++ ;
if ( l == r ) {
now->sum = old->sum + v ;
return ;
}
int m = mid ;
if ( x <= m ) {
now->c[1] = old->c[1] ;
insert ( old->c[0] , now->c[0] , x , v , lson ) ;
} else {
now->c[0] = old->c[0] ;
insert ( old->c[1] , now->c[1] , x , v , rson ) ;
}
now->pushup () ;
}
inline int query ( Node* now , int x , int l , int r ) {
int ans = 0 ;
while ( l < r ) {
int m = mid ;
if ( x <= m ) {
now = now->c[0] ;
r = m ;
} else {
ans += now->c[0]->sum ;
now = now->c[1] ;
l = m + 1 ;
}
}
ans += now->sum ;
return ans ;
}
} ;
namespace LCT {
struct Node* null ;
struct Node {
Node* c[2] ;
Node* f ;
int flip ;
int maxv , v ;
int maxidx , idx ;
inline void newnode ( int val , int id ) {
c[0] = c[1] = f = null ;
flip = 0 ;
maxv = v = val ;
maxidx = idx = id ;
}
inline void reverse () {
if ( this == null ) return ;
swap ( c[0] , c[1] ) ;
flip ^= 1 ;
}
inline bool isroot () {
return f == null || f->c[0] != this && f->c[1] != this ;
}
inline void up () {
if ( this == null ) return ;
maxv = v ;
maxidx = idx ;
if ( c[0]->maxv > maxv ) {
maxv = c[0]->maxv ;
maxidx = c[0]->maxidx ;
}
if ( c[1]->maxv > maxv ) {
maxv = c[1]->maxv ;
maxidx = c[1]->maxidx ;
}
}
inline void down () {
if ( this == null ) return ;
if ( flip ) {
c[0]->reverse () ;
c[1]->reverse () ;
flip = 0 ;
}
}
inline void signdown () {
if ( !isroot () ) f->signdown () ;
down () ;
}
inline void setc ( Node* o , int d ) {
c[d] = o ;
o->f = this ;
}
inline void rot ( int d ) {
Node* p = f ;
Node* g = f->f ;
p->setc ( c[d] , !d ) ;
if ( !p->isroot () ) g->setc ( this , p == g->c[1] ) ;
else f = g ;
setc ( p , d ) ;
p->up () ;
}
inline Node* splay () {
signdown () ;
while ( !isroot () ) {
if ( f->isroot () ) rot ( this == f->c[0] ) ;
else {
if ( f == f->f->c[0] ) {
if ( this == f->c[0] ) f->rot ( 1 ) , rot ( 1 ) ;
else rot ( 0 ) , rot ( 1 ) ;
} else {
if ( this == f->c[1] ) f->rot ( 0 ) , rot ( 0 ) ;
else rot ( 1 ) , rot ( 0 ) ;
}
}
}
up () ;
return this ;
}
inline Node* access () {
Node* o = this ;
Node* x = null ;
for ( ; o != null ; x = o , o = o->f ) {
o->splay ()->setc ( x , 1 ) ;
o->up () ;
}
return splay () ;
}
inline void makeroot () {
access ()->reverse () ;
}
inline Node* findroot () {
Node* o = access () ;
for ( ; o->c[0] != null ; o = o->c[0] ) o->down () ;
return o ;
}
inline void cut () {
access () ;
c[0] = c[0]->f = null ;
up () ;
}
inline bool sameroot ( Node* o ) {
return findroot () == o->findroot () ;
}
inline void link ( Node* o ) {
//if ( this == o || sameroot ( o ) ) return ;
makeroot () ;
f = o ;
}
inline void cut ( Node* o ) {
//if ( !sameroot ( o ) ) return ;
makeroot () ;
o->cut () ;
}
inline int ask ( Node* o ) {
o->makeroot () ;
return access ()->maxidx ;
}
} ;
Node pool[MAXN + MAXE] ;
Node* node[MAXN] ;
Node* edge[MAXE] ;
Node* cur ;
void init () {
cur = pool ;
null = cur ++ ;
null->newnode ( 0 , 0 ) ;
}
} ;
struct Edge {
int u , v , w ;
bool operator < ( const Edge& a ) const {
return w > a.w ;
}
} ;
Edge E[MAXE] ;
int a[MAXE] ;
int n , m , q ;
int search1 ( int x , int l , int r ) {
while ( l < r ) {
int m = ( l + r ) >> 1 ;
if ( a[m] >= x ) r = m ;
else l = m + 1 ;
}
return l ;
}
int search2 ( int x , int l , int r ) {
while ( l < r ) {
int m = ( l + r + 1 ) >> 1 ;
if ( a[m] <= x ) l = m ;
else r = m - 1 ;
}
return l ;
}
void scanf ( int& x , char c = 0 ) {
while ( ( c = getchar () ) < '0' ) ;
x = c - '0' ;
while ( ( c = getchar () ) >= '0' ) x = x * 10 + c - '0' ;
}
void solve () {
int l , r ;
LCT :: init () ;
PST :: init () ;
scanf ( n ) ;
scanf ( m ) ;
PST :: build ( PST :: node[0] , 1 , m ) ;
For ( i , 1 , m ) {
scanf ( E[i].u ) ;
scanf ( E[i].v ) ;
scanf ( E[i].w ) ;
a[i] = E[i].w ;
}
sort ( a + 1 , a + m + 1 ) ;
sort ( E + 1 , E + m + 1 ) ;
For ( i , 1 , n ) {
LCT :: node[i] = LCT :: cur ++ ;
LCT :: node[i]->newnode ( 0 , 0 ) ;
}
For ( i , 1 , m ) {
LCT :: edge[i] = LCT :: cur ++ ;
LCT :: edge[i]->newnode ( E[i].w , i ) ;
}
For ( i , 1 , m ) {
int u = E[i].u ;
int v = E[i].v ;
PST :: insert ( PST :: node[i - 1] , PST :: node[i] , m - i + 1 , E[i].w , 1 , m ) ;
if ( LCT :: node[u]->sameroot ( LCT :: node[v] ) ) {
int idx = LCT :: node[u]->ask ( LCT :: node[v] ) ;
LCT :: edge[idx]->cut ( LCT :: node[E[idx].u] ) ;
LCT :: edge[idx]->cut ( LCT :: node[E[idx].v] ) ;
PST :: insert ( PST :: node[i] , PST :: node[i] , m - idx + 1 , -E[idx].w , 1 , m ) ;
}
LCT :: edge[i]->link ( LCT :: node[u] ) ;
LCT :: edge[i]->link ( LCT :: node[v] ) ;
}
int ans = 0 ;
scanf ( "%d" , &q ) ;
while ( q -- ) {
scanf ( l ) ;
scanf ( r ) ;
l -= ans ;
r -= ans ;
l = m - search1 ( l , 1 , m ) + 1 ;
r = search2 ( r , 1 , m ) ;
ans = PST :: query ( PST :: node[l] , r , 1 , m ) ;
printf ( "%d\n" , ans ) ;
}
}
int main () {
int T ;
scanf ( T ) ;
while ( T -- ) solve () ;
return 0 ;
}