zoukankan      html  css  js  c++  java
  • 主席树 STL+二分【p3939】数颜色

    Description

    小 C 的兔子不是雪白的,而是五彩缤纷的。每只兔子都有一种颜色,不同的兔子可能有 相同的颜色。小 C 把她标号从 (1)(n)(n) 只兔子排成长长的一排,来给他们喂胡萝卜吃。 排列完成后,第 (i) 只兔子的颜色是 (a_i)

    俗话说得好,“萝卜青菜,各有所爱”。小 C 发现,不同颜色的兔子可能有对胡萝卜的 不同偏好。比如,银色的兔子最喜欢吃金色的胡萝卜,金色的兔子更喜欢吃胡萝卜叶子,而 绿色的兔子却喜欢吃酸一点的胡萝卜……为了满足兔子们的要求,小 C 十分苦恼。所以,为 了使得胡萝卜喂得更加准确,小 C 想知道在区间 ([l_j,r_j]) 里有多少只颜色为 (c_j) 的兔子。

    不过,因为小 C 的兔子们都十分地活跃,它们不是很愿意待在一个固定的位置;与此同 时,小 C 也在根据她知道的信息来给兔子们调整位置。所以,有时编号为 (x_j)(x_j+1) 的两 只兔子会交换位置。 小 C 被这一系列麻烦事给难住了。你能帮帮她吗?

    Input

    从标准输入中读入数据。 输入第 1 行两个正整数 (n,m)

    输入第 2 行 (n) 个正整数,第 (i) 个数表示第 (i) 只兔子的颜色 (a_i)

    输入接下来 (m) 行,每行为以下两种中的一种:

    • (1 l_j r_j c_j)” :询问在区间 ([l_j,r_j]) 里有多少只颜色为 (c_j) 的兔子;
    • (2 x_j)”: (x_j)(x_j+1) 两只兔子交换了位置。

    Output

    输出到标准输出中。

    对于每个 1 操作,输出一行一个正整数,表示你对于这个询问的答案。

    woc,写了主席树.结果T了4个点,尝试大力卡常也没过QAQ.

    主席树(80pts)

    对于颜色建树.

    考虑到主席树的性质是维护前缀.

    所以我们可以直接查询,可以直接修改.

    修改操作是这样的

    可能叫build会比较奇怪

    build(root[l],root[l],1,300000,col[l],-1);
    build(root[l],root[l],1,300000,col[l+1],1);
    

    这个应该不是很难理解.(如果你会主席树的话.)

    不理解的话,再想想主席树的性质好了.

    80pts代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define R register
    using namespace std;
    inline void in(int &x)
    {
    	int f=1;x=0;char s=getchar();
    	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }
    void print(int x)
    {
    	if(x<0)
    	{
    		putchar('-');
    		x=-x;
    	}
    	if(x>9)print(x/10);
    	putchar(x%10+'0');
    }
    int sum[20000000],lson[20000000],rson[20000000],root[20000000];
    int cnt,n,m,col[500003];
    void build(int lastroot,int &nowroot,int l,int r,int pos,int k)
    {
    	nowroot=++cnt;
    	sum[nowroot]=sum[lastroot]+k;
    	lson[nowroot]=lson[lastroot];
    	rson[nowroot]=rson[lastroot];
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	if(pos<=mid)
    		build(lson[lastroot],lson[nowroot],l,mid,pos,k);
    	else 
    		build(rson[lastroot],rson[nowroot],mid+1,r,pos,k);
    }
    int query(int lastroot,int nowroot,int l,int r,int pos)
    {
    	if(l==r)return sum[nowroot]-sum[lastroot];
    	int mid=(l+r)>>1;
    	if(pos<=mid) return query(lson[lastroot],lson[nowroot],l,mid,pos);
    	else return query(rson[lastroot],rson[nowroot],mid+1,r,pos);
    }
    int main()
    {
    	in(n),in(m);
    	for(R int i=1;i<=n;i++)
    	{
    		in(col[i]);
    		build(root[i-1],root[i],1,300000,col[i],1);
    	}
    	for(R int i=1,opt,l,r,k;i<=m;i++)
    	{
    		in(opt);
    		if(opt==1)
    		{
    			in(l),in(r),in(k);
    			print(query(root[l-1],root[r],1,300000,k));
    			putchar('
    ');
    		}
    		else
    		{
    			in(l);
    			build(root[l],root[l],1,300000,col[l],-1);
    			build(root[l],root[l],1,300000,col[l+1],1);
    			swap(col[l],col[l+1]);
    		}
    	}
    }
    

    Vector+二分 (100pts)

    (Vector)记录每个颜色出现的位置,然后二分.

    代码

    #include<vector>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define R register
    #define maxn 300010
    #define inf 2147483640
    using namespace std;
    inline void in(int &x)
    {
        int f=1;x=0;char s=getchar();
        while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
        while(isdigit(s)){x=x*10+s-'0';s=getchar();}
        x*=f;
    }
    vector < int > col[maxn] ;
    int n , init[maxn] , m ;  
    inline void work(int l , int r , int x)
    {
        int posl = lower_bound(col[x].begin() , col[x].end() , l) - col[x].begin() ;
        int posr = upper_bound(col[x].begin() , col[x].end() , r) - col[x].begin() - 1 ;
        printf("%d",posr-posl+1); 
    }
    inline void work(int x)
    {
        int l = x , r = x + 1 ; 
        if(init[l] == init[r]) return ; 
        int posl = lower_bound(col[init[l]].begin() , col[init[l]].end() , l) - col[init[l]].begin() ;
        int posr = lower_bound(col[init[r]].begin() , col[init[r]].end() , r) - col[init[r]].begin() ;
        col[init[l]][posl] ++ ; 
        col[init[r]][posr] -- ; 
        swap(init[l] , init[r]) ; 
    }
    int main()
    {
        in(n),in(m) ; int opt , l , r , x ; 
        for(int i = 1 ; i <= n ; ++i) in(init[i]),col[init[i]].push_back(i); 
        for(int i = 1 ; i <= m ; ++i)
        {
            in(opt); 
            if(opt == 1) in(l),in(r),in(x) , work(l , r , x) ; 
            else in(x),work(x) ; 
        }
        return 0 ; 
    }
    
  • 相关阅读:
    AGC041
    二分图 学习笔记
    区间DP 学习笔记
    3月21日考试 题解(数据结构+区间DP+贪心)
    Tarjan 做题总结
    3月15日考试 题解(数学+背包+线段树)
    差分约束 学习笔记
    Tarjan算法 学习笔记
    拓扑排序 学习笔记
    并查集 学习笔记
  • 原文地址:https://www.cnblogs.com/-guz/p/9857605.html
Copyright © 2011-2022 走看看