zoukankan      html  css  js  c++  java
  • 1760:树上数颜色

    1760:树上数颜色

    时间限制: 3000 ms 内存限制: 524288 KB
    提交数: 35 通过数: 9

    【题目描述】
    送你一棵n个点的树,树根为1。一开始每个点上有一个1∼n 的颜色ci,不同点颜色可以相同。

    现在有 q 次操作, 分为两种类型:

    1 u l r:询问子树 u 中有多少种在 l 到 r 之间的颜色至少出现了一次;

    2 u c:将 u 的颜色修改为 c。

    部分测试点要求强制在线。

    【输入】
    第一行三个整数n,q,t,分别表示树的点数,操作的个数和是否强制在线。

    t=0表示不强制在线,t=1表示强制在线。

    接下来一行nn个整数 ci,表示每个点的初始颜色。

    接下来n−1行,每行两个整数ui;vi表示一条ui到vi的边。

    接下来q行,每行四个或三个整数,表示一个操作。

    当t=1时,需要对第一个数以外的其他数异或上一次询问的答案lastans,初始时lastans=0。

    【输出】
    对于每个询问输出一行一个整数,表示答案。

    【输入样例】
    5 5 0
    5 5 2 5 5
    5 1
    2 5
    4 2
    3 5
    1 2 2 3
    2 5 1
    1 1 1 5
    2 3 2
    1 3 1 5
    【输出样例】
    0
    3
    1
    【提示】
    【输入样例2】
    5 5 1
    4 1 1 5 4
    5 1
    3 5
    2 3
    4 3
    2 5 4
    2 2 2
    1 3 1 5
    2 1 2
    1 1 2 7
    【输出样例2】
    3
    1


    【数据规模和约定】

    对于前20%的数据,n,q≤5000n,q≤5000。

    对于前40%的数据,n,q≤50000n,q≤50000。

    对于另20%的数据,没有修改操作。

    对于另20%的数据,t=0t=0。

    对于100%的数据,1≤n,q≤1000001≤n,q≤100000。

     【题解】

    考虑对于每种颜色,在子树中出现过就是他在dfn[u]到low[u]之间,但要求重复的颜色只算一次,可以将所有同一种颜色的节点按照dfn升序排列,树上差分维护,将所有点的权值加一,并将相邻的点的lca权值减一。对每个颜色建一颗线段树来维护区间求和。考虑使用树状数组套线段树优化,询问直接询问即可。实现较为复杂,代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    set <int> s[N];
    int n,q,t,last[N],size,f[N][20],m,dfn[N],low[N],dep[N],cnt,dui[N],col[N],lastans;
    struct pigu
    {
        int dao,ne;
    }a[N<<1];
    inline void lingjiebiao(int x,int y)
    {
        a[++size].dao=y;
        a[size].ne=last[x];
        last[x]=size;
    }
    inline int read()
    {
        int x=0,f=1;
        char c=getchar();
        while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();} 
        while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
        return x*f;
    }
    int sum[N<<8],lc[N<<8],rc[N<<8],ge,root[N];
    inline int get_lca(int x,int y)
    {
        if(dep[x]<dep[y])
            swap(x,y);
        for(int i=19;i>=0;i--)
            if(dep[f[x][i]]>=dep[y]) 
                x=f[x][i];
        if(x==y) return x;
        for(int i=19;i>=0;i--)
            if(f[x][i]!=f[y][i])
                x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    inline void dfs(int now,int fa)
    {
        dfn[now]=++cnt;dui[cnt]=now;
        f[now][0]=fa;dep[now]=dep[fa]+1;
        for(int i=1;f[f[now][i-1]][i-1];i++) f[now][i]=f[f[now][i-1]][i-1];
        for(int i=last[now];i;i=a[i].ne)
        {
            if(a[i].dao==fa) continue;
            dfs(a[i].dao,now);
        }
        low[now]=cnt;
    }
    inline int lowbit(int x)
    {
        return x&(-x);
    }
    inline void modify(int &now,int l,int r,int zai,int sf)
    {
        if(!now) now=++ge;
        sum[now]+=sf;
        if(l==r) return;
        int mid=(l+r)>>1;
        if(zai<=mid) modify(lc[now],l,mid,zai,sf);
        else modify(rc[now],mid+1,r,zai,sf);
    }
    inline void gainei(int se,int zai,int pan)
    {
        set <int>::iterator it;
        it=s[se].find(zai);
        if(it!=s[se].begin())
        {
            it--;
            int ga=dui[*it];
            int gu=get_lca(dui[zai],dui[*it]);
            for(int i=se;i<=n;i+=lowbit(i)) modify(root[i],1,n,dfn[gu],-pan);
            it++;it++;
            if(it!=s[se].end())
            {    
                gu=get_lca(ga,dui[*it]);
                for(int i=se;i<=n;i+=lowbit(i)) modify(root[i],1,n,dfn[gu],pan);    
            }
            it--;
        }
        it++;
        if(it!=s[se].end())
        {
            int gu=get_lca(dui[zai],dui[*it]);
            for(int i=se;i<=n;i+=lowbit(i)) modify(root[i],1,n,dfn[gu],-pan);
            it--;
        }
    }
    inline void insert(int se,int zai)
    {
        s[se].insert(dfn[zai]);gainei(se,dfn[zai],1);
        for(int i=se;i<=n;i+=lowbit(i))
            modify(root[i],1,n,dfn[zai],1);
    }
    inline int query(int now,int l,int r,int L,int R)
    {
        if(!now) return 0;
        if(l>=L&&r<=R)
        {
            return sum[now];
        }
        int mid=(l+r)>>1,daan=0;
        if(L<=mid) daan+=query(lc[now],l,mid,L,R);
        if(R>=mid+1) daan+=query(rc[now],mid+1,r,L,R);
        return daan;
    }
    inline void shan(int se,int zai)
    {
        gainei(se,dfn[zai],-1);s[se].erase(dfn[zai]);
        for(int i=se;i<=n;i+=lowbit(i)) modify(root[i],1,n,dfn[zai],-1);
    } 
    int main()
    {
        n=read();q=read();t=read();
        for(int i=1;i<=n;i++) col[i]=read();
        for(int i=1,x,y;i<=n-1;i++)
        {
            x=read();y=read();
            lingjiebiao(x,y);
            lingjiebiao(y,x);
        }
        dfs(1,0);
        for(int i=1;i<=n;i++) insert(col[i],i);
        for(int i=1,x,y,z,u;i<=q;i++)
        {
            x=read();y=read();z=read();
            if(t==1) y^=lastans,z^=lastans;
            if(x==2)
            {
                shan(col[y],y);col[y]=z;
                insert(col[y],y);
            }
            else
            {
                u=read();
                if(t==1) u^=lastans;
                int ans=0;
                for(int i=u;i;i-=lowbit(i))
                    ans+=query(root[i],1,n,dfn[y],low[y]);
                for(int i=z-1;i;i-=lowbit(i))
                    ans-=query(root[i],1,n,dfn[y],low[y]);
                lastans=ans;
                cout<<ans<<"
    ";
            }
        }
    }
    View Code
  • 相关阅读:
    Java框架spring学习笔记(十七):事务操作
    Java框架spring 学习笔记(十六):c3p0连接池的配置以及dao使用jdbcTemplate
    Java框架spring 学习笔记(十五):操作MySQL数据库
    Java框架spring 学习笔记(十四):注解aop操作
    Java框架spring 学习笔记(十三):log4j介绍
    Java框架spring 学习笔记(十二):aop实例操作
    Java框架spring 学习笔记(十一):aop相关概念
    Java框架spring 学习笔记(十):bean管理(注解和配置文件混合使用)
    Java框架spring 学习笔记(九):Spring的bean管理(@Required、@Component、@Autowired、@Resource注解)
    Java框架spring 学习笔记(八):注入对象类型属性
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12210739.html
Copyright © 2011-2022 走看看