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<<"\n";
        }
    }
}

原文地址:https://www.cnblogs.com/betablewaloot/p/12210739.html

时间: 2024-10-20 19:15:07

1760:树上数颜色的相关文章

BZOJ2120: 数颜色

2120: 数颜色 Time Limit: 6 Sec  Memory Limit: 259 MBSubmit: 1394  Solved: 516[Submit][Status] Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col.为了满足墨墨的要求,你知道你需要干什么了吗? Inpu

cogs 1901. [国家集训队2011]数颜色

Cogs 1901. [国家集训队2011]数颜色 ★★★   输入文件:nt2011_color.in   输出文件:nt2011_color.out   简单对比时间限制:0.6 s   内存限制:512 MB [试题来源] 2011中国国家集训队命题答辩 [问题描述] 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令:1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔.2. R P Col 把第P支画笔替换为

bzoj 2120 数颜色

2120: 数颜色 Time Limit: 6 Sec  Memory Limit: 259 MBSubmit: 5039  Solved: 2012 Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col.为了满足墨墨的要求,你知道你需要干什么了吗? Input 第1行两个整数N,M,分别

bzoj 2120: 数颜色 线段树套平衡树

/************************************************************** Problem: 2120 User: wangyucheng Language: C++ Result: Time_Limit_Exceed ****************************************************************/ #include<iostream> #include<cstdio> #incl

[BZOJ2120][BZOJ2453]数颜色

[BZOJ2120]数颜色 试题描述 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col.为了满足墨墨的要求,你知道你需要干什么了吗? 输入 第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数.第2行N个整数,分别代表初始画笔排中第i支画笔的颜色.第3行到第2+M行,每行分别代表墨墨会做的一件

【BZOJ】【2120】数颜色

莫队算法 分块大法吼 这题乍一看跟HH的项链很像啊……只是多了一个修改操作……然而我就不会做了 分块来搞吧!像糖果公园那样= =按左端点所在块为第一关键字,右端点所在块为第二关键字,修改时间为第三关键字…… 然后暴力搞呗…… 照着糖果公园的代码yy了半天终于是yy出来了……然而跪了…… RE & TLE:我是傻逼!c1和c2的声明跟cmd[5]放在一起了!应该是整型声明成char了! Orz lct1999 ,编译时加 -Wall 就会提醒这些傻逼错误……新技能get√ 1 /*********

bzoj 2120: 数颜色(带修改的莫队算法)

2120: 数颜色 Time Limit: 6 Sec  Memory Limit: 259 MB Submit: 2908  Solved: 1130 [Submit][Status][Discuss] Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col.为了满足墨墨的要求,你知道你需

[Bzoj2120]数颜色 (非正解 )(莫队)

2120: 数颜色 Time Limit: 6 Sec  Memory Limit: 259 MBSubmit: 6286  Solved: 2489[Submit][Status][Discuss] Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col.为了满足墨墨的要求,你知道你需要干

[luogu]P3939 数颜色[二分]

[luogu]P3939 数颜色 题目描述 小 C 的兔子不是雪白的,而是五彩缤纷的.每只兔子都有一种颜色,不同的兔子可能有 相同的颜色.小 C 把她标号从 1 到 n 的 n 只兔子排成长长的一排,来给他们喂胡萝卜吃. 排列完成后,第 i 只兔子的颜色是 ai?. 俗话说得好,“萝卜青菜,各有所爱”.小 C 发现,不同颜色的兔子可能有对胡萝卜的 不同偏好.比如,银色的兔子最喜欢吃金色的胡萝卜,金色的兔子更喜欢吃胡萝卜叶子,而 绿色的兔子却喜欢吃酸一点的胡萝卜……为了满足兔子们的要求,小 C 十