Jiajia 和 Wind 是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia 、Wind 和孩子们决定在家里玩捉迷藏游戏。他们的家很大且构造很奇特,由 N 个屋子和 N−1 条双向走廊组成,这 N−1 条走廊的分布使得任意两个屋子都互相可达。游戏是这样进行的,孩子们负责躲藏,Jiajia 负责找,而 Wind 负责操纵这 N 个屋子的灯。在起初的时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性, Jiajia 希望知道可能的最远的两个孩子的距离(即最远的两个关灯房间的距离)。 我们将以如下形式定义每一种操作: C(hange)i 改变第 i 个房间的照明状态,若原来打开,则关闭;若原来关闭,则打开。 G(ame) 开始一次游戏,查询最远的两个关灯房间的距离。
第一行包含一个整数 N ,表示房间的个数,房间将被编号为 1,2,3,…,N 的整数。接下来 N−1 行每行两个整数 a,b ,表示房间 a 与房间 b 之间有一条走廊相连。接下来一行包含一个整数 Q ,表示操作次数。接着 Q 行,每行一个操作,如上文所示。
对于每一个操作 Game ,输出一个非负整数到 hide.out
,表示最远的两个关灯房间的距离。若只有一个房间是关着灯的,输出 0 ;若所有房间的灯都开着,输出 −1 。
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
4
3
3
4
对于 100% 的数据, N≤105,M≤5×105 。
动态点分治。
首先处理出所有点到所有分治根节点的距离 dis[ dfn[i][j] ][ j ] ,按照 dfs 序插入到每个分治根节点对应的动态开点线段树中。(这是为了方便查询该节点属于分治根节点的哪一个子树)
然后对于每一个分治根节点 root ,经过该节点的路径长度最大值为:
其中 mx 为最大值所处下标, l[x] 表示 x 所处子树在 dfs 序上的左端点, r[x] 表示 x 所处子树在 dfs 序上的右端点。
上式的意思是如果 rt 开着并且只有一个子树有关的灯,那么就没有路径经过 rt 。其他情况就是以 rt 为分治根的子树距离的最大值 + 不在该最大值节点所在子树的节点距离的最大值。
然后修改 x 的时候就可以遍历所有的包含节点 x 的分治子树的根节点,修改 x 在线段树上的存在性(如果关灯则加入 x , 开灯则删除 x ,即为讲 x 所在的下标的值置为 −inf ),然后更新该分治根节点的答案。
查询的时候可以再开一颗线段树,存储每个分治根节点的答案,单点修改,查询 1∼n 的最大值(好像也可以用手写堆)
复杂度 O((n+m)log22n) 。
代码很长(共 8KB),写的时候要注意细节和边界情况。当然我的代码有一些地方可以简化。
不要犯一些制杖性错误。
/**************************************************************
Problem: 1095
User: infinityedge
Language: C++
Result: Accepted
Time:32113 ms
Memory:214388 kb
****************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
#define eps 1e-10
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
struct edge {
int to, w, nxt;
} e[200005];
int h[100005], cnt;
void addedge(int x, int y) {
cnt++; e[cnt].to = y; e[cnt].nxt = h[x]; h[x] = cnt;
cnt++; e[cnt].to = x; e[cnt].nxt = h[y]; h[y] = cnt;
}
int n, m;
int vis[100005], siz[100005], dep[100005], tp[100005], ans[100005], Ans[100005], dis[100005][17], dfn[100005][17], root[100005];
int b[100005], Dfn[100005], end[100005], Ct, cnt_open;
vector<int> vec[100005];
int N, rt, ct, ansroot;
struct node{
int l, r, lc, rc;
P dat;
}d[100005 * 20 * 2 * 2];
int seg_sz;
void pushup(int k){
d[k].dat = make_pair(-inf, 0);
if(d[k].lc) d[k].dat = d[d[k].lc].dat;
if(d[k].rc) {
if(d[d[k].rc].dat.first > d[k].dat.first) d[k].dat = d[d[k].rc].dat;
}
}
void ins(int &k, int l, int r, int pos, int x){
if(k == 0) k = ++seg_sz;
d[k].l = l, d[k].r = r;
if(l == r) {
d[k].dat = make_pair(x, pos);
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) ins(d[k].lc, l, mid, pos, x);
else ins(d[k].rc, mid + 1, r, pos, x);
pushup(k);
}
void modify(int k, int pos, int x){
if(k == 0) return;
if(d[k].l == d[k].r){
d[k].dat = make_pair(x, pos);
return;
}
int mid = (d[k].l + d[k].r) >> 1;
if(pos <= mid) modify(d[k].lc, pos, x);
else modify(d[k].rc, pos, x);
pushup(k);
}
P query(int k, int l, int r){
if(k == 0) return make_pair(-inf, 0);
if(l <= d[k].l && d[k].r <= r){
return d[k].dat;
}
int mid = (d[k].l + d[k].r) >> 1;
P sum = make_pair(-inf, 0);
if(l <= mid) {
P tmp = query(d[k].lc, l, r);
if(tmp.first > sum.first) sum = tmp;
}
if(r > mid) {
P tmp = query(d[k].rc, l, r);
if(tmp.first > sum.first) sum = tmp;
}
return sum;
}
void dfs_root(int x, int f){
siz[x] = 1; int mx = 0;
for(int i = h[x]; i; i = e[i].nxt){
if(e[i].to == f || vis[e[i].to]) continue;
dfs_root(e[i].to, x);
mx = max(mx, siz[e[i].to]);
siz[x] += siz[e[i].to];
}
if(max(mx, N - siz[x] - 1) <= N / 2) rt = x;
}
void dfs_size(int x, int f){
siz[x] = 1;
for(int i = h[x]; i; i = e[i].nxt){
if(e[i].to == f || vis[e[i].to]) continue;
dfs_size(e[i].to, x);
siz[x] += siz[e[i].to];
}
}
void dfs_tag(int x, int f, int de){
dep[x] = de;
for(int i = h[x]; i; i = e[i].nxt){
if(e[i].to == f || vis[e[i].to]) continue;
tp[e[i].to] = rt;
dfs_tag(e[i].to, x, de);
}
}
void dfs_ans(int x, int f){
dis[x][dep[x]] = dis[f][dep[x]] + 1;
dfn[x][dep[x]] = ++ct;
ins(root[rt], 1, N, dfn[x][dep[x]], dis[x][dep[x]]);
for(int i = h[x]; i; i = e[i].nxt){
if(e[i].to == f || vis[e[i].to]) continue;
dfs_ans(e[i].to, x);
}
}
void solve(int x, int cur){
dfs_root(x, 0);
Dfn[rt] = end[rt] = ++Ct;
dfs_size(rt, 0);
dfs_tag(rt, 0, cur);
ins(root[rt], 1, N, 1, 0);
ct = 1;
for(int i = h[rt]; i; i = e[i].nxt){
if(vis[e[i].to]) continue;
vec[rt].push_back(ct);
dfs_ans(e[i].to, rt);
}
vec[rt].push_back(ct + 1);
P r1 = query(root[rt], 1, N);
int r = lower_bound(vec[rt].begin(), vec[rt].end(), r1.second) - vec[rt].begin();
int l = r - 1;
l = vec[rt][l], r = vec[rt][r];
P r2 = make_pair(-inf, 0), r3 = make_pair(-inf, 0);
if(l >= 1) r2 = query(root[rt], 1, l);
if(r < N) r3 = query(root[rt], r + 1, N);
if(r3.first > r2.first) r2 = r3;
Ans[rt] = ans[rt] = r1.first + r2.first;
vis[rt] = 1;
int trt = rt;
for(int i = h[trt]; i; i = e[i].nxt){
if(vis[e[i].to]) continue;
if(siz[e[i].to] == 1) continue;
N = siz[e[i].to];
solve(e[i].to, cur + 1);
Ans[trt] = max(Ans[trt], Ans[e[i].to]);
end[trt] = Ct;
}
ins(ansroot, 1, n, Dfn[trt], Ans[trt]);
}
void solvemodify(int x){
if(b[x] == 0){
b[x] = 1; cnt_open --;
int mxdep = dep[x], rtp = tp[x];
if(Dfn[x]) {
mxdep--;
// printf("%d ", Ans[x]);
modify(root[x], 1, -inf);
N = d[root[x]].r;
P r1 = query(root[x], 1, N);
int r = lower_bound(vec[x].begin(), vec[x].end(), r1.second) - vec[x].begin();
int l = r - 1;
l = vec[x][l], r = vec[x][r];
P r2 = make_pair(-inf, 0), r3 = make_pair(-inf, 0);
if(l >= 1) r2 = query(root[x], 1, l);
if(r < N) r3 = query(root[x], r + 1, N);
if(r3.first > r2.first) r2 = r3;
if(b[x] == 1 && r2.first == 0) r1.first = 0;
Ans[x] = ans[x] = r1.first + r2.first;
modify(ansroot, Dfn[x], Ans[x]);
// printf("%d\n", Ans[x]);
}
for(int i = mxdep; i >= 0; i --){
// printf("%d ", Ans[rtp]);
modify(root[rtp], dfn[x][i], 0);
N = d[root[rtp]].r;
P r1 = query(root[rtp], 1, N);
int r = lower_bound(vec[rtp].begin(), vec[rtp].end(), r1.second) - vec[rtp].begin();
int l = r - 1;
l = vec[rtp][l], r = vec[rtp][r];
P r2 = make_pair(-inf, 0), r3 = make_pair(-inf, 0);
if(l >= 1) r2 = query(root[rtp], 1, l);
if(r < N) r3 = query(root[rtp], r + 1, N);
if(r3.first > r2.first) r2 = r3;
if(b[rtp] == 1 && r2.first == 0) r1.first = 0;
ans[rtp] = r1.first + r2.first;
// printf("%d %d %d %d ", r1.first, r1.second, r2.first, r2.second);
modify(ansroot, Dfn[rtp], ans[rtp]);
Ans[rtp] = query(ansroot, Dfn[rtp], end[rtp]).first;
// printf("%d\n", Ans[rtp]);
rtp = tp[rtp];
}
}else{
b[x] = 0; cnt_open ++;
int mxdep = dep[x], rtp = tp[x];
if(Dfn[x]) {
mxdep--;
// printf("%d ", Ans[x]);
modify(root[x], 1, 0);
N = d[root[x]].r;
P r1 = query(root[x], 1, N);
int r = lower_bound(vec[x].begin(), vec[x].end(), r1.second) - vec[x].begin();
int l = r - 1;
l = vec[x][l], r = vec[x][r];
P r2 = make_pair(-inf, 0), r3 = make_pair(-inf, 0);
if(l >= 1) r2 = query(root[x], 1, l);
if(r < N) r3 = query(root[x], r + 1, N);
if(r3.first > r2.first) r2 = r3;
if(b[x] == 1 && r2.first == 0) r1.first = 0;
Ans[x] = ans[x] = r1.first + r2.first;
modify(ansroot, Dfn[x], Ans[x]);
// printf("%d\n", Ans[x]);
}
for(int i = mxdep; i >= 0; i --){
// printf("%d ", Ans[rtp]);
modify(root[rtp], dfn[x][i], dis[x][i]);
N = d[root[rtp]].r;
P r1 = query(root[rtp], 1, N);
int r = lower_bound(vec[rtp].begin(), vec[rtp].end(), r1.second) - vec[rtp].begin();
int l = r - 1;
l = vec[rtp][l], r = vec[rtp][r];
P r2 = make_pair(-inf, 0), r3 = make_pair(-inf, 0);
if(l >= 1) r2 = query(root[rtp], 1, l);
if(r < N) r3 = query(root[rtp], r + 1, N);
if(r3.first > r2.first) r2 = r3;
if(b[rtp] == 1 && r2.first == 0) r1.first = 0;
ans[rtp] = r1.first + r2.first;
// printf("%d %d %d %d ", r1.first, r1.second, r2.first, r2.second);
modify(ansroot, Dfn[rtp], ans[rtp]);
Ans[rtp] = query(ansroot, Dfn[rtp], end[rtp]).first;
// printf("%d\n", Ans[rtp]);
rtp = tp[rtp];
}
}
}
int main() {
// freopen("test.in", "r", stdin);
// freopen("test.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i < n; i ++) {
int x, y;
scanf("%d%d", &x, &y);
addedge(x, y);
}
N = n; cnt_open = n;
solve(1, 0);
scanf("%d", &m);
char ch[5];
for(int i = 1; i <= m; i ++){
scanf("%s", ch);
if(ch[0] == 'G'){
if(cnt_open == 1){
printf("0\n");
continue;
}
if(cnt_open == 0){
printf("-1\n");
continue;
}
printf("%d\n", query(ansroot, 1, n).first);
}else{
int x;
scanf("%d", &x);
solvemodify(x);
}
}
return 0;
}