题目描述
给出\(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\)操作输出结果
输入输出样例
输入样例#1:
9 81 21 32 42 95 97 98 96 81 30 81 61 70 21 90 21 9
输出样例#1:
-18-12-1
说明
For \(1/3\) of the test cases, \(N=5000, Q=400000\).
For \(1/3\) of the test cases, \(N=10000, Q=300000\).
For \(1/3\) of the test cases, \(N=100000, Q=100000\).
思路:对于操作\(1\),显然我们可以利用线段树的单点修改操作来实现,对于操作\(2\),要求求\(1\)到\(v\)的路径上的第一个黑点,那么我们可以考虑维护两点之间路径之间是黑点的点的深度最浅值,可以用树链剖分+线段树来实现。
代码:
#include#include #include #define maxn 100007#define ls rt<<1#define rs rt<<1|1using namespace std;const int inf=1e9+7;int n,m,num,top[maxn],cnt,head[maxn],d[maxn],size[maxn],id[maxn];int minn[maxn<<2],fa[maxn],son[maxn],a[maxn],w[maxn];inline int qread() { char c=getchar();int num=0,f=1; for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num*f;}struct node { int v,nxt;}e[maxn<<1];inline void ct(int u, int v) { e[++num].v=v; e[num].nxt=head[u]; head[u]=num;}void dfs1(int u) { size[u]=1; for(int i=head[u];i;i=e[i].nxt) { int v=e[i].v; if(v!=fa[u]) { d[v]=d[u]+1; fa[v]=u; dfs1(v); size[u]+=size[v]; if(size[v]>size[son[u]]) son[u]=v; } }}void dfs2(int u, int t) { id[u]=++cnt; top[u]=t; a[cnt]=u; if(son[u]) dfs2(son[u],t); for(int i=head[u];i;i=e[i].nxt) { int v=e[i].v; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); }}inline void pushup(int rt) { minn[rt]=min(minn[ls],minn[rs]);}void build(int rt, int l, int r) { if(l==r) { minn[rt]=inf; return; } int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); pushup(rt);}void modify(int rt, int l, int r, int L) { if(l==r) { if(w[id[L]]^=1) minn[rt]=l; else minn[rt]=inf; return; } int mid=(l+r)>>1; if(L<=mid) modify(ls,l,mid,L); else modify(rs,mid+1,r,L); pushup(rt);}int cmin(int rt, int l, int r, int L, int R) { if(L>r||R >1,ans=inf; if(L<=mid) ans=min(ans,cmin(ls,l,mid,L,R)); if(R>mid) ans=min(ans,cmin(rs,mid+1,r,L,R)); return ans;}int query(int x, int y) { int fx=top[x],fy=top[y],ans=inf; while(fx!=fy) { if(d[fx] id[y]) swap(x,y); ans=min(ans,cmin(1,1,cnt,id[x],id[y])); return ans;}int main() { n=qread(),m=qread(); for(int i=1,u,v;i