【题目描述】
给出N个点的一棵树(N-1条边),节点有白有黑,初始全为白。有两种操作:
0 i : 改变某点的颜色(原来是黑的变白,原来是白的变黑)
1 v : 询问1到v的路径上的第一个黑点,若无,输出-1
【输入格式】
第一行 N,Q,表示N个点和Q个操作
第二行到第N行N-1条无向边
再之后Q行,每行一个操作”0 i” 或者”1 v” (1 ≤ i, v ≤ N).
【输出格式】
对每个1 v操作输出结果
SampleInput S a m p l e I n p u t
9 8
1 2
1 3
2 4
2 9
5 9
7 9
8 9
6 8
1 3
0 8
1 6
1 7
0 2
1 9
0 2
1 9
SampleOutput S a m p l e O u t p u t
-1
8
-1
2
-1
【题意分析】
树上路径查询&&修改?果断上树剖。
修改颜色的时候用异或,这里线段树维护的是此区间内第一个出现的黑点。因为是单点修改,所以标记下传啥的都不需要~~直接上区间最值线段树。
如果白点的话就赋值INF,防止参与查询。
其他,好像也没什么可注意的了?
水题一道
Code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<cstring>
#include<vector>
#include<algorithm>
#define int long long
#define MAXN 120000
#define INF 1 << 30
using namespace std;
struct Front_Link_Star{
int to,next;
}edge[MAXN << 1];
int tree[MAXN << 2],head[MAXN << 1],color[MAXN],id[MAXN],son[MAXN],depth[MAXN];
int father[MAXN],rk[MAXN],top[MAXN],size[MAXN],dfn,n,q,cnt;
inline void connect (int u,int v){
edge[++cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt;
}
//上推
inline void push_up (int now){
tree[now] = min (tree[now << 1],tree[now << 1 | 1]);
}
//建树
void build (int now,int tl,int tr){
if (tl == tr){
tree[now] = INF;
return;
}
int mid = (tl + tr) >> 1;
build (now << 1,tl,mid);
build (now << 1 | 1,mid+1,tr);
push_up (now);
}
//修改
void update (int now,int tl,int tr,int left,int right,int change){
if (right < tl || tr < left)return;
if (left <= tl && tr <= right){
if (change == 1)tree[now] = tl;
else tree[now] = INF;
return;
}
int mid = (tl + tr) >> 1;
update (now << 1,tl,mid,left,right,change);
update (now << 1 | 1,mid+1,tr,left,right,change);
push_up (now);
}
//查询
int query (int now,int tl,int tr,int left,int right){
if (right < tl || tr < left)return INF;
if (left <= tl && tr <= right)return tree[now];
int res = INF,mid = (tl + tr) >> 1;
res = min (query (now << 1,tl,mid,left,right),res);
res = min (query (now << 1 | 1,mid+1,tr,left,right),res);
return res;
}
//询问的是根节点开始的路径,所以交换什么的都不需要了~~
inline int Query_Range (int x){
int tmp = INF;
while (top[x] != 1){
tmp = min (tmp,query (1,1,n,id[top[x]],id[x]));
x = father[top[x]];
}
tmp = min (tmp,query (1,1,n,1,id[x]));
return tmp;
}
//基本操作
void DFS1 (int now,int fa,int d){
father[now] = fa;
depth[now] = d;
size[now] = 1;
int maxson = -1;
for (register int i = head[now];i;i = edge[i].next){
int v = edge[i].to;
if (v == fa)continue;
DFS1 (v,now,d+1);
size[now] += size[v];
if (size[v] > maxson){
maxson = size[v];
son[now] = v;
}
}
}
void DFS2 (int now,int top_heavy){
top[now] = top_heavy;
id[now] = ++dfn;
rk[dfn] = now;
if (!son[now])return;
DFS2 (son[now],top_heavy);
for (register int i = head[now];i;i = edge[i].next){
int v = edge[i].to;
if (v != father[now] && v != son[now])DFS2 (v,v);
}
}
signed main (){
scanf ("%lld%lld",&n,&q);
for (register int i = 1;i < n;i++){
int x,y;
scanf ("%lld%lld",&x,&y);
connect (x,y);
connect (y,x);
}
DFS1 (1,0,1);
DFS2 (1,1);
build (1,1,n);
while (q--){
int type;
scanf ("%lld",&type);
if (type == 0){
int x;
scanf ("%lld",&x);
color [x] ^= 1;//异或修改颜色
update (1,1,n,id[x],id[x],color[x]);
}
if (type == 1){
int x;
scanf ("%lld",&x);
int ans = Query_Range (x);
if (ans == INF)puts ("-1");
else printf ("%lld\n",rk[ans]);
//输出后要映射一下!!
}
}
return 0;
}