传送门:【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 ; }