题目链接:https://www.spoj.com/problems/QTREE3/
感谢Konjak谷弱博客的启发
题目分析
0 i : change the color of the i-th node (from white to black, or from black to white);
1 v : ask for the id of the first black node on the path from node 1 to node v. if it doesn’t exist, you may return -1 as its result.
0 i : 改变某点的颜色(原来是黑的变白,原来是白的变黑)
1 v : 询问1到v的路径上的第一个黑点,若无,输出-1
一开始自己看错题了,一直以为是边,结果发现怎么写都是错的,后来发现如果是边的话也可以,关键是线段树中的返回值操作要会写。直接树剖,不过要注意线段树中的change和query,主要是分类写,详细看代码吧。(最近写了一些线段树和树剖的题后发现,最难的是线段树中pushup和pushdown操作QWQ)
程序代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (tree[rt].l+((tree[rt].r-tree[rt].l)>>1))
using namespace std;
const int MAXN=1e5+5;
struct arr{
long long l,r,id;
}tree[MAXN<<2];
struct ar1{
int aa,nd,nx,co,id;
}bot[MAXN*2];
int n,cnt,tot,t,q,ans;
int pos[MAXN],id[MAXN],son[MAXN],fa[MAXN],son_cost[MAXN];
int w[MAXN],deep[MAXN],top[MAXN],sz[MAXN],head[MAXN];
inline int read(){
int x=0,w=1;char ch;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();
return x*w;
}
inline void insert_add(int a,int b,int id){ bot[++cnt].aa=a;bot[cnt].nd=b; bot[cnt].id=id;bot[cnt].nx=head[a]; head[a]=cnt; }
void build(int rt,int l,int r) {
tree[rt].l=l;tree[rt].r=r;
if(tree[rt].l==tree[rt].r) { tree[rt].id=0;return ;}
int midd=l+((r-l)>>1);
build(ls,l,midd);build(rs,midd+1,r);
}
void dfs1(int x,int fat,int dep) {
deep[x]=dep;fa[x]=fat;sz[x]=1;
for(register int i=head[x];i;i=bot[i].nx) {
int v=bot[i].nd;
if(v!=fat) {
dfs1(v,x,dep+1);
sz[x]+=sz[v];
if(son[x]==0||sz[son[x]]<sz[v]) son[x]=v;
}
}
}
void dfs2(int x,int tp) {
top[x]=tp;pos[x]=++tot;id[tot]=x;w[x]=0;
if(son[x]==0) return ;
dfs2(son[x],tp);
for(register int i=head[x];i;i=bot[i].nx) {
int v=bot[i].nd;
if(v!=fa[x]&&v!=son[x]) dfs2(v,v);
}
}
void updata(int rt,int l) {
if(tree[rt].l==tree[rt].r) {
if(tree[rt].id==0) tree[rt].id=tree[rt].l;
else tree[rt].id=0;
return;
}
if(l<=mid) updata(ls,l);
else updata(rs,l);
if(tree[ls].id) //跟新的时候也要判断一下
tree[rt].id=tree[ls].id;
else
if(tree[rs].id) tree[rt].id=tree[rs].id;
else
tree[rt].id=0;
}
int query(int l,int r,int rt) {
if(tree[rt].l==l&&r==tree[rt].r) return tree[rt].id;
if(r<=mid) return query(l,r,ls);
else if(l>mid) return query(l,r,rs);
else {//重点是这几个判断,因为是说的返回第一个,所以我们在这样里判断一下
int t1=query(l,mid,ls);if(t1)return t1;
int t2=query(mid+1,r,rs);if(t2) return t2;
return 0;
}
}
int Query(int t1,int t2) {//普通的Query,先存一个t,返回的是tree[].id,而在id[]存的才是原来的那个数,因为我们线段树是按照pos来建的
int u=t1,v=t2,ans=-1,ta;
while(top[u]!=top[v]) {
if(deep[top[u]]>deep[v]) swap(u,v);
int t=query(pos[top[v]],pos[v],1);
if(t) ans=id[t]; v=fa[top[v]];
}
int t;
if(deep[u]>deep[v]) swap(u,v);
t=query(pos[u],pos[v],1);
if(t) ans=id[t];
return ans;
}
int main(){
n=read();q=read();
for(register int i=1;i<n;++i) {
int u=read(),v=read();
insert_add(u,v,i);insert_add(v,u,i);
}
dfs1(1,1,1);
dfs2(1,1);
build(1,1,n);
for(register int i=1;i<=q;++i) {
int ok=read(),v=read();
if(ok) {
int ans=Query(1,v);
if(ans) printf("%d\n",ans);
else cout<<-1<<endl;
}
else {
updata(1,pos[v]);
}
}
return 0;
}