• Qtree3


    ## 题目描述

    给出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操作输出结果

    输入输出样例

    输入样例#1: 复制

    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: 复制

    -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.

    Solution

    这题显然是树链剖分,先把dfs序处理出来,但线段树存什么呢?可以发现,若以1为根,进行dfs序,这样1到每个点之间的最早出现的黑点,显然是dfs序最小值,这样线段树存最小值就行了,我们还要把线段树上的点映射回树中结点。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll(x) (x*2)
    #define rr(x) (x*2+1)
    using namespace std;
    struct Node
    {
        int to,next;
    }a[201001];
    int len,last[200110],siz[201010],son[201100],dep[201001],fa[200010],yuan[200101];
    int id[201010],cnt,n,sum[400101],top[400101],mn[400110];
    void add(int a1,int a2)
    {
        a[++len].to=a2;
        a[len].next=last[a1];
        last[a1]=len;
    }
    void dfs1(int x,int father)
    {
        int mxson=-1;siz[x]=1;
        for(int i=last[x];i;i=a[i].next)
        {
            int to=a[i].to;
            if(to==father) continue;
            dep[to]=dep[x]+1;
            fa[to]=x;
            dfs1(to,x);
            siz[x]+=siz[to];
            if(siz[to]>mxson) son[x]=to,mxson=siz[to];
        }
    }
    void dfs2(int x,int topf)
    {
        id[x]=++cnt;
        yuan[cnt]=x;
        top[x]=topf;
        if(!son[x]) return;
        dfs2(son[x],topf);
        for(int i=last[x];i;i=a[i].next)
        {
            int to=a[i].to;
            if(to==fa[x]||to==son[x]) continue;
            dfs2(to,to);
        }
    }
    void pushup(int node){mn[node]=min(mn[ll(node)],mn[rr(node)]);}
    void gai(int node,int l,int r,int pos)
    {
        if(l==r) {sum[node]^=1;if(sum[node]==1) mn[node]=l;else mn[node]=1e9;return;}
        int mid=(l+r)/2;
        if(pos<=mid) gai(ll(node),l,mid,pos);
        else gai(rr(node),mid+1,r,pos);
        pushup(node);
    }
    int cha(int node,int l,int r,int left,int right)
    {
        if(l>=left&&r<=right) return mn[node];
        int mid=(l+r)/2,ans=1e9;
        if(left<=mid) ans=min(ans,cha(ll(node),l,mid,left,right));
        if(right>mid) ans=min(ans,cha(rr(node),mid+1,r,left,right));
        return ans;
    }
    int cha1(int x,int y)
    {
        int ans=1e9;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            ans=min(ans,cha(1,1,n,id[top[x]],id[x]));
            x=fa[top[x]];
        }
        if(dep[x]>dep[y]) swap(x,y);
        ans=min(ans,cha(1,1,n,id[x],id[y]));
        if(ans==1e9)
        return -1;
        return yuan[ans];
    }
    int main()
    {	
        for(int i=0;i<=400000;i++)
        mn[i]=1e9;
        int q,x,y,opt;
        cin>>n>>q;
        for(int i=1;i<n;i++)
        scanf("%d%d",&x,&y),add(x,y),add(y,x);
        dep[1]=1;
        dfs1(1,0);
        dfs2(1,1);
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d",&opt,&x);
            if(opt==0)
            gai(1,1,n,id[x]);
            else
            printf("%d
    ",cha1(1,x));
        }
    }
    

    博主蒟蒻,可以随意转载,但必须附上原文链接k-z-j

  • 相关阅读:
    爬虫:Scrapy15
    爬虫:Scrapy14
    爬虫:Scrapy13
    爬虫:Scrapy12
    爬虫:Scrapy11
    爬虫:Scrapy10
    爬虫:Scrapy9
    线段树基础
    [USACO08DEC]秘密消息Secret Message
    阅读理解
  • 原文地址:https://www.cnblogs.com/kzj-pwq/p/9617191.html
Copyright © 2020-2023  润新知