SPOJ QTREE3 - Query on a tree again!

题目链接: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;
}

猜你喜欢

转载自blog.csdn.net/tangzhide123yy/article/details/81783585
今日推荐