zoukankan      html  css  js  c++  java
  • [jzoj 3175] 数树数 解题报告 (树链剖分)

    interlinkage:

    https://jzoj.net/senior/#main/show/3175

    description:

    给定一棵N 个节点的树,标号从1~N。每个点有一个权值。要求维护两种操作:
    1. C i x(0<=x<2^31) 表示将i 点权值变为x
    2. Q i j x(0<=x<2^31) 表示询问i 到j 的路径上有多少个值为x的节点

    solution:

    • 链剖
    • 把颜色离散化,对每种颜色分别搞一颗线段树
    • 直接搞会炸空间,因此要动态开点
    • 感觉树上莫队好像也可以

    code

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int N=4e5+15;
    int n,q,tot,cnt,tim;
    int head[N],dep[N],siz[N],wson[N],fa[N],top[N],dfn[N],rt[N<<1],color[N];
    int lx[N<<4],rx[N<<4],sum[N<<4];
    ll a[N],b[N<<1];
    struct EDGE
    {
        int to,nxt;
    }edge[N];
    struct QUE
    {
        int op;
        int x,y;
        ll v;
    }t[N];
    inline ll read()
    {
        char ch=getchar();ll s=0,f=1;
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    }
    void add(int u,int v)
    {
        edge[++tot]=(EDGE){v,head[u]};
        head[u]=tot;
    }
    void dfs1(int x,int pre)
    {
        dep[x]=dep[pre]+1;siz[x]=1;fa[x]=pre;
        for (int i=head[x];i;i=edge[i].nxt)
        {
            int y=edge[i].to;
            if (y==pre) continue;
            dfs1(y,x);
            siz[x]+=siz[y];
            if (!wson[x]||siz[wson[x]]<siz[y]) wson[x]=y;
        }
    }
    void dfs2(int x,int tp)
    {
        top[x]=tp;dfn[x]=++tim;
        if (wson[x]) dfs2(wson[x],tp);
        for (int i=head[x];i;i=edge[i].nxt)
        {
            int y=edge[i].to;
            if (y==fa[x]||y==wson[x]) continue;
            dfs2(y,y);
        }
    }
    void upd(int o)
    {
        sum[o]=sum[lx[o]]+sum[rx[o]];
    }
    void update(int &o,int l,int r,int pos,int x)
    {
        if (!o) o=++cnt;
        if (l==r)
        {
            sum[o]+=x;
            return;
        }
        int mid=l+r>>1;
        if (pos<=mid) update(lx[o],l,mid,pos,x);
        else update(rx[o],mid+1,r,pos,x);
        upd(o);
    }
    void change(int x,int v)
    {
        if (color[x])
        {
            update(rt[color[x]],1,n,dfn[x],-1);
        }
        color[x]=v;
        update(rt[v],1,n,dfn[x],1);
    }
    int query(int o,int l,int r,int x,int y)
    {
        if (!o) return 0;
        if (l>=x&&r<=y) return sum[o];
        int mid=l+r>>1,re=0;
        if (x<=mid) re+=query(lx[o],l,mid,x,y);
        if (y>mid) re+=query(rx[o],mid+1,r,x,y);
        return re;
    }
    int query_path(int x,int y,int v)
    {
        int res=0;
        while (top[x]!=top[y])
        {
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            res+=query(rt[v],1,n,dfn[top[x]],dfn[x]);
            x=fa[top[x]];
        }
        if (dep[x]<dep[y]) swap(x,y);
        res+=query(rt[v],1,n,dfn[y],dfn[x]);
        return res;
    }
    int main()
    {
        //freopen("tree.in","r",stdin);
        n=read();q=read();
        int len=0;
        for (int i=1;i<=n;i++) a[i]=read(),b[++len]=a[i];
        for (int i=1;i<n;i++)
        {
            int u=read(),v=read();
            add(u,v);add(v,u);
        }
        dfs1(1,0);
        dfs2(1,1);
        char s[5];
        for (int i=1;i<=q;i++)
        {
            scanf("%s",s);
            if (s[0]=='C')
            {
                t[i].op=1;
                t[i].x=read();t[i].v=read();
            }
            if (s[0]=='Q')
            {
                t[i].op=2;
                t[i].x=read();t[i].y=read();t[i].v=read();
            }
            b[++len]=t[i].v;
        }
        sort(b+1,b+1+len);
        len=unique(b+1,b+1+len)-b-1;
        for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+len,a[i])-b;
        for (int i=1;i<=q;i++) t[i].v=lower_bound(b+1,b+1+len,t[i].v)-b;
        for (int i=1;i<=n;i++) change(i,a[i]);
        for (int i=1;i<=q;i++)
        {
            if (t[i].op==1)
            {
                change(t[i].x,t[i].v);
            }
            if (t[i].op==2)
            {
                printf("%d
    ",query_path(t[i].x,t[i].y,t[i].v));
            }
        }
        return 0;
    }
  • 相关阅读:
    表单全选,不选和反选
    利用js改变宽,高等属性
    点击显示与隐藏
    改变div的不同属性
    给三个不同的div变色
    经典排序算法实现
    基本排序算法的实现
    排序的概念及分类实现
    #和##运算符实例
    #pragma预处理实例
  • 原文地址:https://www.cnblogs.com/xxzh/p/10677655.html
Copyright © 2011-2022 走看看