题目描述
给出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操作输出结果
输入输出样例
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
-1 8 -1 2 -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.
(假装我是在spoj上做的一样hhh)
贼裸的树剖+线段树,,,练手题(今天建模能力为0,全在码模板hhh)
#include<bits/stdc++.h> #define ll long long #define maxn 100005 #define pb push_back using namespace std; vector<int> g[maxn]; int dfn[maxn],dy[maxn],pos; int siz[maxn],f[maxn],opt; int cl[maxn],n,m,son[maxn],dc=0; int sum[maxn<<2|1],mxp[maxn<<2|1]; int le,ri; void dfs1(int x,int fa){ f[x]=fa,siz[x]=1; int to; for(int i=g[x].size()-1;i>=0;i--){ to=g[x][i]; if(to==fa) continue; dfs1(to,x),siz[x]+=siz[to]; if(!son[x]||siz[to]>siz[son[x]]) son[x]=to; } } void dfs2(int x,int tp){ dfn[x]=++dc,dy[dc]=x,cl[x]=tp; if(son[x]) dfs2(son[x],tp); int to; for(int i=g[x].size()-1;i>=0;i--){ to=g[x][i]; if(to==f[x]||to==son[x]) continue; dfs2(to,to); } } void update(int o,int l,int r){ if(l==r){ sum[o]^=1; if(sum[o]) mxp[o]=dy[l]; else mxp[o]=0; return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; if(le<=mid) update(lc,l,mid); else update(rc,mid+1,r); if(sum[lc]) mxp[o]=mxp[lc]; else mxp[o]=mxp[rc]; sum[o]=sum[lc]+sum[rc]; } int query(int o,int l,int r){ if(l>=le&&r<=ri) return mxp[o]; int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1,an=0; if(le<=mid) an=query(lc,l,mid); if(!an&&ri>mid) an=query(rc,mid+1,r); return an; } inline void tolt(int x){ le=dfn[x],update(1,1,n); } inline int answer(int x){ int an=-1,po; while(x){ le=dfn[cl[x]],ri=dfn[x]; po=query(1,1,n); if(po) an=po; x=f[cl[x]]; } return an; } int main(){ int uu,vv; scanf("%d%d",&n,&m); for(int i=1;i<n;i++){ scanf("%d%d",&uu,&vv); g[uu].pb(vv),g[vv].pb(uu); } dfs1(1,0); dfs2(1,1); while(m--){ scanf("%d%d",&opt,&pos); if(opt) printf("%d\n",answer(pos)); else tolt(pos); } return 0; }