您的位置:首页 > 运维架构

bzoj 1018 线段树维护连通性

2015-02-21 22:14 246 查看
本题将一道LCT的题特殊化(支持加边和删边,询问图的连通性),将图变成了2×m的网格图,然后就神奇地可以用线段树来维护。

对于每个区间[l,r],维护其四个角落之间的连通性(仅仅通过[l,r]这段的边构建起的连通性)。

查询[l,r]时,先计算出[1,l-1],[l,r],[r+1,c]这三个线段的连通性,然后将[l,r]的四个角变成并查集的4个点,先用[l,r]中的6种关系更新,在看是否可以从左上角的点通过左边区间绕道左下角,以及从右上角通过右边区间绕道右下角,该并的并起来后直接看查询的点是否在一个集合即可。

/**************************************************************
Problem: 1018
User: idy002
Language: C++
Result: Accepted
Time:1472 ms
Memory:2840 kb
****************************************************************/

#include <cstdio>
#include <iostream>
#define maxn 100010
#define AB 1
#define AC 2
#define AD 4
#define BC 8
#define BD 16
#define CD 32
using namespace std;

// a b
// c d

typedef unsigned Stat;

Stat stat[maxn];
int son[maxn][2], ntot, root;

int c;
bool er[3][maxn], ed[maxn];

Stat merge( Stat l, Stat r, int mid ) {
Stat ab = ((l&AB)&&(r&AB)&&er[1][mid]) || ((l&AD)&&(r&BC)&&er[2][mid]) ? AB : 0;
Stat cd = ((l&CD)&&(r&CD)&&er[2][mid]) || ((l&BC)&&(r&AD)&&er[1][mid]) ? CD : 0;
Stat ad = ((l&AB)&&(r&AD)&&er[1][mid]) || ((l&AD)&&(r&CD)&&er[2][mid]) ? AD : 0;
Stat bc = ((l&CD)&&(r&BC)&&er[2][mid]) || ((l&BC)&&(r&AB)&&er[1][mid]) ? BC : 0;
Stat ac = (l&AC) || ((l&AB)&&(l&CD)&&(er[1][mid])&&(er[2][mid])&&(r&AC)) ? AC : 0;
Stat bd = (r&BD) || ((r&AB)&&(r&CD)&&(er[1][mid])&&(er[2][mid])&&(l&BD)) ? BD : 0;
return ab | ac | ad | bc | bd | cd;
}
void update( int nd, int lf, int rg ) {
stat[nd] = merge( stat[son[nd][0]], stat[son[nd][1]], (lf+rg)>>1 );
}
int build( int lf, int rg ) {
if( lf>rg ) return 0;
int nd = ++ntot;
if( lf==rg ) {
stat[nd] = AB | CD;
return nd;
}
int mid = (lf+rg)>>1;
son[nd][0] = build( lf, mid );
son[nd][1] = build( mid+1, rg );
update( nd, lf, rg );
return nd;
}
void modify( int x, int nd, int lf, int rg ) {
if( lf==rg ) {
stat[nd] = AB | CD;
if( ed[lf] )
stat[nd] |= AC | BD | AD | BC;
return;
}
int mid = (lf+rg)>>1;
if( x<=mid ) modify(x,son[nd][0],lf,mid);
else modify(x,son[nd][1],mid+1,rg);
update(nd,lf,rg);
}
Stat query( int L, int R, int nd, int lf, int rg ) {
if( L<=lf&&rg<=R ) return stat[nd];
int mid = (lf+rg)>>1;
if( R<=mid ) return query( L, R, son[nd][0], lf, mid );
if( L>mid ) return query( L, R, son[nd][1], mid+1, rg );
Stat lstat = query( L, R, son[nd][0], lf, mid );
Stat rstat = query( L, R, son[nd][1], mid+1, rg );
return merge(lstat,rstat,mid);
}

int fa[5];
void init() {
for( int i=1; i<=4; i++ ) fa[i]=i;
}
int find( int i ) {
return fa[i]==i ? i : fa[i]=find(fa[i]);
}
void unon( int a, int b ) {
a = find(a);
b = find(b);
fa[a] = b;
}
int main() {
scanf( "%d", &c );
root = build( 1, c );
while(1) {
char ch[10];

scanf( "%s", ch );
if( ch[0]=='E' ) return 0;
int ax, ay, bx, by;
scanf( "%d%d%d%d", &ax, &ay, &bx, &by );

if( ch[0]=='A' ) {
if( ay>by ) {
swap( ax, bx );
swap( ay, by );
}
Stat sl=0, sc=0, sr=0;
if( ay>1 ) sl = query(1,ay-1,root,1,c);
sc = query(ay,by,root,1,c);
if( by<c ) sr = query(by+1,c,root,1,c);

init();
if( sc&AB ) unon( 1, 2 );
if( sc&AC ) unon( 1, 3 );
if( sc&AD ) unon( 1, 4 );
if( sc&BC ) unon( 2, 3 );
if( sc&BD ) unon( 2, 4 );
if( sc&CD ) unon( 3, 4 );
if( (sl&BD) && er[1][ay-1] && er[2][ay-1] ) unon( 1, 3 );
if( (sr&AC) && er[1][by]   && er[2][by]   ) unon( 2, 4 );

bool ok = false;
if( ax==1 && bx==1 ) {
ok = find( 1 ) == find( 2 );
} else if( ax==1 && bx==2 ) {
ok = find( 1 ) == find( 4 );
} else if( ax==2 && bx==1 ) {
ok = find( 3 ) == find( 2 );
} else if( ax==2 && bx==2 ) {
ok = find( 3 ) == find( 4 );
}

printf( "%s\n", ok ? "Y" : "N" );
} else {
bool *p;
if( ax==bx ) {
p = &er[ax][min(ay,by)];
} else {
p = &ed[ay];
}
*p = ch[0]=='O';
modify( ay, root, 1, c );
if( ay!=by )
modify( by, root, 1, c );
}
}
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: