SPOJ QTREE3 - Query on a tree again!

13 篇文章 0 订阅
6 篇文章 0 订阅

题目链接: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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
洛谷的SPOJ需要注册一个SPOJ账号并进行绑定才能进行交题。您可以按照以下步骤进行注册: 1. 打开洛谷网站(https://www.luogu.com.cn/)并登录您的洛谷账号。 2. 在网站顶部导航栏中找到“题库”选项,将鼠标悬停在上面,然后选择“SPOJ”。 3. 在SPOJ页面上,您会看到一个提示,要求您注册SPOJ账号并进行绑定。点击提示中的链接,将会跳转到SPOJ注册页面。 4. 在SPOJ注册页面上,按照要求填写您的用户名、密码和邮箱等信息,并完成注册。 5. 注册完成后,返回洛谷网站,再次进入SPOJ页面。您会看到一个输入框,要求您输入刚刚注册的SPOJ用户名。输入用户名后,点击“绑定”按钮即可完成绑定。 现在您已经成功注册并绑定了SPOJ账号,可以开始在洛谷的SPOJ题库上刷题了。祝您顺利完成编程练习!\[1\]\[2\] #### 引用[.reference_title] - *1* *3* [(洛谷入门系列,适合洛谷新用户)洛谷功能全解](https://blog.csdn.net/rrc12345/article/details/122500057)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [luogu p7492 序列](https://blog.csdn.net/zhu_yin233/article/details/122051384)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值