Description
捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind和孩子们决定在家里玩
捉迷藏游戏。他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋
子都互相可达。游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯。在起初的
时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要
求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia希望知道可能的最远的两
个孩子的距离(即最远的两个关灯房间的距离)。 我们将以如下形式定义每一种操作: C(hange) i 改变第i个房
间的照明状态,若原来打开,则关闭;若原来关闭,则打开。 G(ame) 开始一次游戏,查询最远的两个关灯房间的
距离。
Input
第一行包含一个整数N,表示房间的个数,房间将被编号为1,2,3…N的整数。接下来N-1行每行两个整数a, b,
表示房间a与房间b之间有一条走廊相连。接下来一行包含一个整数Q,表示操作次数。接着Q行,每行一个操作,如
上文所示。
Output
对于每一个操作Game,输出一个非负整数到hide.out,表示最远的两个关灯房间的距离。若只有一个房间是关
着灯的,输出0;若所有房间的灯都开着,输出-1。
Sample Input
8
1 2
2 3
3 4
3 5
3 6
6 7
6 8
7
G
C 1
G
C 2
G
C 1
G
1 2
2 3
3 4
3 5
3 6
6 7
6 8
7
G
C 1
G
C 2
G
C 1
G
Sample Output
4
3
3
4
3
3
4
HINT
对于100%的数据, N ≤100000, M ≤500000。
Source
线段树+括号序列
用括号序列表示一棵树的方法类似于dfs序,进入时加入一个[,访问完时加入一个]
然后两个点之间的距离就是未匹配括号数
发现一定匹配的消去之后一定长这样]]]]]]]][[[[[[[[[[
然后线段树维护即可,为了维护答案还要维护到两边的一些东西,具体见代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100010;
const int INF = 1e9 + 7;
inline int read()
{
int sc = 0; char ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) sc = sc * 10 + ch - '0', ch = getchar();
return sc;
}
struct edge
{
int to, nxt;
}e[MAXN << 1];
int n, Q, head[MAXN], cnt, pos[MAXN], tot, num[MAXN * 3], vis[MAXN], now;
char opt[2];
inline void add(int x, int y) { e[ ++cnt ].to = y; e[ cnt ].nxt = head[ x ]; head[ x ] = cnt; }
inline void addedge(int x, int y) { add( x, y ); add( y, x ); }
inline void dfs(int x, int fa)
{
num[ ++tot ] = -1;
pos[ num[ ++tot ] = x ] = tot;
for( int i = head[ x ] ; i ; i = e[ i ].nxt ) if( e[ i ].to ^ fa ) dfs( e[ i ].to, x );
num[ ++tot ] = -2;
}
struct node
{
int c1, c2, l1, l2, r1, r2, ans;
//c1---] c2---[
//l1---max( ] + [ ) l2---max( [ - ] )
//r1---max( ] + [ ) r2---max( ] - [ )
inline void cal(int x)
{
c1 = c2 = 0;
l1 = l2 = r1 = r2 = ans = -INF;
if( x == -1 ) c2 = 1;
else if( x == -2 ) c1 = 1;
else if( vis[ x ] == 1 ) l1 = l2 = r1 = r2 = 0;
}
}t[MAXN * 3 << 2];
inline node merge(node a, node b)
{
node c;
c.c1 = a.c1 + max( 0, b.c1 - a.c2 );
c.c2 = b.c2 + max( 0, a.c2 - b.c1 );
c.ans = max( max( a.ans, b.ans ), max( a.r1 + b.l2, a.r2 + b.l1 ) );
c.l1 = max( a.l1, max( b.l1 - a.c2 + a.c1, b.l2 + a.c1 + a.c2 ) );
c.l2 = max( a.l2, b.l2 + a.c2 - a.c1 );
c.r1 = max( b.r1, max( a.r1 - b.c1 + b.c2, a.r2 + b.c1 + b.c2 ) );
c.r2 = max( b.r2, a.r2 + b.c1 - b.c2 );
return c;
}
inline void update(int x, int l, int r, int pos)
{
if( l == r ) { t[ x ].cal( num[ l ] ); return ; }
int mid = l + r >> 1;
if( pos <= mid ) update( x << 1, l, mid, pos );
else update( x << 1 | 1, mid + 1, r, pos );
t[ x ] = merge( t[ x << 1 ], t[ x << 1 | 1 ] );
}
inline void build(int x, int l, int r)
{
if( l == r )
{
t[ x ].cal( num[ l ] );
return ;
}
int mid = l + r >> 1;
build( x << 1, l, mid );
build( x << 1 | 1, mid + 1, r );
t[ x ] = merge( t[ x << 1 ], t[ x << 1 | 1 ] );
}
int main()
{
now = n = read();
for( int i = 1 ; i <= n ; i++ ) vis[ i ] = 1;
for( int i = 1 ; i < n ; i++ ) addedge( read(), read() );
dfs( 1, 0 );
build( 1, 1, tot );
Q = read();
while( Q-- )
{
scanf( "%s", opt );
if( opt[ 0 ] == 'G' )
{
if( !now ) puts( "-1" );
else if( now == 1 ) puts( "0" );
else printf( "%d\n", t[ 1 ].ans );
}
else
{
int x = read();
now += vis[ x ] = -vis[ x ];
update( 1, 1, tot, pos[ x ] );
}
}
}