十一届院赛 I题 我要10个G

题目给出n个点,只有n-1条边,而且都是连通的,那么就可以得出是一棵树。
那就变成了裸的树剖。
套模板,完事。
#include<stdio.h>
#include<algorithm>
#include<string>
#include<string.h>
#include<queue>
#include<vector>
#include<stack>
#include<math.h>
#include<map>
#include<iostream>
using namespace std;
#define maxn 300050
struct edge
{
    int en,next;
}E[maxn*2];
struct node
{
    int l;
    int r;
    int smin;
}tree[maxn*8];
int a[maxn];
int dep[maxn];  //节点深度
int fa[maxn];   //节点父亲
int siz[maxn];  //以V为跟的节点数目
int son[maxn];  //V节点的重儿子
int p[maxn],fp[maxn];  //p[v],节点v在线段树中的位置,fp[v]是p的反向映射
int top[maxn];      // v节点的重链的顶端
int head[maxn],cnt,pos,n,q;  //邻接表
void addedge(int st,int en)
{
    E[cnt].en=en;
    E[cnt].next=head[st];
    head[st]=cnt;
    cnt++;
}
void inti()
{
    cnt=0;pos=0;
    memset(son,-1,sizeof(son));
    memset(a,0,sizeof(a));
    memset(dep,0,sizeof(dep));
    memset(fa,0,sizeof(fa));
    memset(p,0,sizeof(p));
    memset(siz,0,sizeof(siz));
    memset(head,-1,sizeof(head));
}
void dfs1(int u,int f,int d)
{
    dep[u]=d;
    fa[u]=f;
    siz[u]=1;
    for(int i=head[u];i!=-1;i=E[i].next)
    {
        int v=E[i].en;
        if(v!=f)
        {
            dfs1(v,u,d+1);
            siz[u] += siz[v];
            if(son[u]==-1||siz[v]>siz[son[u]])
                son[u]=v;
        }
    }
}
void pushup(int id)
{
    tree[id].smin=min(tree[id*2].smin,tree[id*2+1].smin);
}
void build(int id,int l,int r)
{
    tree[id].l=l;
    tree[id].r=r;
    if(l==r)
    {
        tree[id].smin=1;
        return ;
    }
    int mid=(l+r)/2;
    build(id*2,l,mid);
    build(id*2+1,mid+1,r);
    pushup(id);
}
void update(int id,int x,int v)
{
    int l=tree[id].l;
    int r=tree[id].r;
    int mid=(l+r)/2;
    if(l==r)
    {
        tree[id].smin=v;
        return ;
    }
    if(l<=x&&x<=mid)
        update(id*2,x,v);
    else if(mid<x&&x<=r)
        update(id*2+1,x,v);
    pushup(id);
}
int querymin(int id,int x,int y)
{
    int l=tree[id].l;
    int r=tree[id].r;
    int mid=(l+r)/2;
    if(x<=l&&r<=y)
        return tree[id].smin;
    if(y<l||x>r)
        return 1e9;
    return min(querymin(id*2,x,y),querymin(id*2+1,x,y));
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=pos++;
    fp[p[u]]=u;
    if(son[u]==-1)
        return ;
    getpos(son[u],sp);
    for(int i=head[u];i!=-1;i=E[i].next)
    {
        int v=E[i].en;
        if(v!=son[u]&&v!=fa[u])
            getpos(v,v);
    }
}
int findmin(int u,int v)
{
    int f1=top[u],f2=top[v];
    int ret=1e9;
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        ret=min(ret,querymin(1,p[f1],p[u]));
        u=fa[f1];
        f1=top[u];
    }
    if(dep[u]>dep[v])
        swap(u,v);
    return min(ret,querymin(1,p[u],p[v]));
}
int main()
{
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        inti();
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            addedge(x,y);
            addedge(y,x);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,0,pos-1);
        while(q--)
        {
            int s,x,y;
            scanf("%d",&s);
            if(s==1)
            {
                scanf("%d%d",&x,&y);
                int ans=findmin(x,y);
                if(ans==1)
                    printf("YES\n");
                else
                    printf("NO\n");
            }
            else if(s==2)
            {
                scanf("%d",&x);
                update(1,p[x],1);
            }
            else
            {
                scanf("%d",&x);
                update(1,p[x],0);
            }
        }
    }
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值