zoukankan      html  css  js  c++  java
  • luogu 5251 图灵机二代 珂朵莉树+树状数组+线段树+ 双指针

    先%一下图灵, 肽巨(exin)了

    (然而我并不想像wlj一样, 把放空间里供着。。。)

    借鉴了一下前几位巨佬的思路。

    思想:(我感觉解释的比较详细)

    第一种操作 :单点修改数字 /应该不用多说

    第二种操作: 区间颜色推平。。。显然要请出我们可耐的珂朵莉(old driver)啊!!!

    第三种操作 : 包含所有颜色 数字和最小的子区间 de数字和

    第四种操作: 不含重复颜色,数字和最大的子区间的数字和

    3, 4 貌似不能维护 所以要单拿出来搞

    考虑双指针法(其实很难考虑到这种方法)
    现在我们把所有颜色相同的一段连续区间放在了一个块里(ODT)
    现在对这些块用双指针

    3、

    一开始左右指针都指向左端点, 现在要找包含所有颜色 数字和最小的子区间 de数字和
    显然我们要用双指针维护|包含所有的颜色|;

    ​ 对于每一次统计答案的过程:

    ​ 每次让右指针向右移直到出现了所有的颜色, 此时再考虑左指针是不是也能向右移一点,直到左指针不能向右移

    4、

    一开始左右指针都指向左端点, 现在要找的是不含重复颜色,|数字和最大的子区间 de数字和| 显然我们要用双指针维护|不含重复颜色|;
    显然一个颜色是无论如何也合法的 所以答案初值赋成区间最大值(用数据结构维护)

    ​ 对于每一次统计答案的过程:

    ​ 此时枚举右指针的位置, 看左指针最小会到哪, 找到第一个合法的位置, 统计答案;

    大概思路就是这样,还有一些珂朵莉的细节要注意一下(比如它返回的哪一块的迭代器),而且很繁琐。。。(表示看到差点吐血)

    具体可以看代码以及注释

    (一个下午+ 一个晚上。。保证自己一个一个打的)

    丑陋的代码 大括号换行之类的就别在意了

    #include <cstdio>
    #include <cstring>
    #include <set> 
    #define IT set<block>::iterator
    #define RR register
    #define N 100001
    using namespace std;
    int n, m ,c, num[N];
    inline int read()
    {
    	int x = 0, f = 1;
    	char ch = getchar();
    	while(ch < '0'||ch > '9')
    	    { if(ch == '-') f = -f; ch = getchar(); }
    	while(ch >= '0'&&ch <= '9')
    	    {x = (x<<1) + (x<<3) + ch-'0'; ch = getchar(); }
    	return f * x;
    }
    /******************************************************************/
    //树状数组  维护区间和 不解释 
    struct Bittree
    {
    	int val[N];
    	inline int lowbit(int x){return x&(-x);}
    	inline int ask(RR int pos)
    	{
    		int res = 0;
    		for(RR int i = pos; i; i -= lowbit(i))
    		     res += val[i];
    		return res;
    	}
    	inline void chenge(RR int pos, RR int v)
    	{
    		for(RR int i = pos; i <= n; i += lowbit(i))
    		   val[i] += v;
    	}
    	inline int ask_(RR int l, RR int r)
    	{
    		return ask(r) - ask(l - 1);
    	}
    }tr1;
    //线段树 维护区间最大值 不解释 
    struct Segment
    {
    	struct node
    	{
    		int l, r, maxx;
    		node *L, *R;
    		node(int l, int r) : l(l), r(r), maxx(0), L(NULL), R(NULL) {}
    		inline int mid(){return (l + r)>>1; }
    		inline int len(){return (r - l + 1); }
    		inline void up() {
    			maxx = max(L->maxx , R->maxx);
    	    }
    	}*root;
    	
    	inline void build(RR node *&k, RR int l, RR int r)
    	{
    		k =new node(l, r);
    		if(l == r) 	{
    			k->maxx = num[l];
    			return ;
    		}
    		int mid = k->mid();
    		build(k->L, k->l, mid);
    		build(k->R, mid + 1, r);
    		k->up();
    	}
    	inline void chenge(RR node *k, RR int pos, RR int val)
    	{
    		if(k->l == k->r)
    		{
    			k->maxx = val;
    			return;
    		}
    		int mid = k->mid();
    		if(pos <= mid)      chenge(k->L, pos, val);
    	    if(pos >= mid +1 )  chenge(k->R, pos, val);
    		k->up();
    	}
    	inline int ask(RR node *k, RR int l, RR int r)
    	{
    		if(l<= k->l && r >= k->r)
    			return k->maxx;
    		int res = 0;
    		int mid = k->mid();
    		if(l <= mid)     res = max(res, ask(k->L, l, r));
    		if(r >= mid + 1) res = max(res, ask(k->R, l, r));
    		return res;
    	}
    }tr2;
    // ODT  emmm 
    struct block
    {
    	int l, r;
        mutable int col;
        block(int l , int r = -1, int col =0) : l(l), r(r), col(col) {}
        friend bool operator < (const block &a, const block &b)
        {
        	return a.l < b.l;
        }
    };
    set< block >s;
    IT split(int pos)//基本操作 
    {
    	IT it = s.lower_bound(block(pos));
    	if(it != s.end() && it->l == pos)
    	  return it;
    	it--;
    	int ll = it->l, rr = it->r;
    	int col = it->col;
    	s.erase( it );
    	s.insert( block(ll, pos - 1, col) );
    	return s.insert( block(pos, rr, col) ).first;
    }
    bool check(IT l, IT r) 
    //   不重复的要求 :要么在一个块  要么邻块  要么之间的所有块都只有一个元素  
    {
    	if(l == r || (++l)-- ==r) return 1;
    	++ l;
    	for(IT i = l; i != r; ++ i)
    	{
    		if(i->r != i->l)return 0;
    	}
    	return 1;
    }
    inline void assign(RR int l, RR int r, RR int col)//基本操作 
    {
    	IT itr = split(r+1), itl = split(l);
    	s.erase(itl, itr);
    	s.insert(block(l, r, col)); 
    }
    /**************************************************************/
    int tmp[N];//颜色桶 
    inline int zh_dou(RR int l, RR int r)// 包含所有颜色  数字和最小的子区间 
    {
    	int ans = 2e9, rest = c;//没统计上的颜色数 
        for(int i = 1; i <= c; i++) tmp[i] = 0;
    	IT itr = split(r+1), itl = split(l), ll, rr;//不透彻的自己学ODT去 
    	--itl;  ll = rr = itl;
    	while(rr != itr)//双指针  若每次操作后右指针未到区间右端 
    	{
    		if(ll != itl)// 这个地方的确难理解...e xin了我好久
    		//考虑上一轮 左指针向左移 直到少一种颜色, 但是你后来又加上了, 
    		//现在要再悔回去  因为本轮右指针右移的前提是还有未统计的颜色 想想看  
    		{
    			--tmp[ll->col];
    			if(!tmp[ll->col]) ++rest;
    		}ll++;
    		while(rest && rr != itr)//还有未统计的颜色 且 右指针能往右移 
    		{
    			++rr; 
    			++tmp[rr->col];
    			if(tmp[rr->col] == 1)--rest; //当这个颜色之前未统计过才能算贡献 
    		}
    		if(rr==itr) break;//到右端点就break掉  此时不能统计答案 
    		while(!rest && ll!=rr)//颜色统计全了后考虑将左指针向左移 直到少一种颜色 
    		{
    			--tmp[ll->col];
    			if(!tmp[ll->col]) ++rest; //此时少了一种颜色 
    			++ll;
    		}
    		if(rest)//将刚刚少的那个颜色返回去 
    		{
    			--ll;  ++ tmp[ll->col]; --rest;
    		}
    		ans = min(ans, tr1.ask_(ll->r, rr->l));
    		//此时就找到一种合法情况,可以统计一次答案,数字和最小,所以所以是左端块的右端点 到 右端块的左端点 
    	} 
    	return  ans == 2e9 ? -1 : ans; 
    }
    inline int w_lj( RR int l, RR int r)// 不含重复颜色,数字和最大的子区间 
    {
        for(int i = 1; i <= c; i++) tmp[i] = 0;
    	int ans = tr2.ask(tr2.root, l, r); //赋为区间最大值 
    	IT itr = split(r + 1), itl = split(l), ll, rr;//不用解释 
    	rr = itl; ll = itl;
    	while(rr != itr)//枚举右指针的位置 
    	{
    		++tmp[rr->col];//对应上一轮的最后rr++ 
    		while(!check(ll, rr)) //不符合不重复的要求   就把左指针往右移 
    	    --tmp[ll->col], ++ll; 
    		while(ll!=rr && tmp[rr->col] > 1) --tmp[ll->col], ++ll;//不光不能有长度大于1 的块 还不能有颜色相同的块 
    		if(ll!=rr) ans = max(ans, tr1.ask_(ll->r,  rr->l)); //此时就可以统计答案了 (合法了) 
    		++rr;// 到下一轮 
    	}
    	return ans;
    
    }
    signed main()//下面应该不用解释 
    {
    	int  l, r, x, y, opt;
    	n = read(); m = read(); c = read();
    	s.insert(block(0, 0, -1)); s.insert(block(n + 1, n + 1, -1));
    	for(RR int i = 1; i <= n; i ++)
    	{
    		num[i] = read();
    		tr1.chenge(i, num[i]);
    	}
    	tr2.build(tr2.root, 1, n);
    	for(RR int i = 1; i <=n; i ++)
    	{
    		int color = read();
    		s.insert(block(i, i, color));
    	}
    	while(m --> 0)
    	{
    		opt = read();
    		if(opt == 1)
    		{
    			x = read(); y = read();
    			tr1.chenge(x, y - tr1.ask_(x, x));
    			tr2.chenge(tr2.root, x, y);
    		}
    		else if(opt == 2)
    		{
    			l = read(); r = read(); x = read();
    			assign(l, r, x);
    		}
    		else if(opt == 3)
    		{
    			l = read(); r = read();
    			int ans = zh_dou(l, r);
    			printf("%d\n", ans);
    		}
    		else 
    		{
    			l = read(); r = read();
    			int ans = w_lj(l, r);
    			printf("%d\n",ans);
    		}	
    	}
    	return 0;
    }
    // 本题的卡常 
    /*
    1 inline rejister
    2 数组开小点
    3 赋初值尽量改for, 不用memset 
    4 换快读, 或fread 
    5 可以尝试用指针
    */
     
    

    原代码

    #include <cstdio>
    #include <cstring>
    #include <set> 
    #define IT set<block>::iterator
    #define RR register
    #define N 100001
    using namespace std;
    int n, m ,c, num[N];
    inline int read()
    {
    	int x = 0, f = 1;
    	char ch = getchar();
    	while(ch < '0'||ch > '9')
    	    { if(ch == '-') f = -f; ch = getchar(); }
    	while(ch >= '0'&&ch <= '9')
    	    {x = (x<<1) + (x<<3) + ch-'0'; ch = getchar(); }
    	return f * x;
    }
    /******************************************************************/
    //树状数组
    struct Bittree
    {
    	int val[N];
    	inline int lowbit(int x){return x&(-x);}
    	inline int ask(RR int pos)
    	{
    		int res = 0;
    		for(RR int i = pos; i; i -= lowbit(i))
    		     res += val[i];
    		return res;
    	}
    	inline void chenge(RR int pos, RR int v)
    	{
    		for(RR int i = pos; i <= n; i += lowbit(i))
    		   val[i] += v;
    	}
    	inline int ask_(RR int l, RR int r)
    	{
    		return ask(r) - ask(l - 1);
    	}
    }tr1;
    //线段树 
    struct Segment
    {
    	struct node
    	{
    		int l, r, maxx;
    		node *L, *R;
    		node(int l, int r) : l(l), r(r), maxx(0), L(NULL), R(NULL) {}
    		inline int mid(){return (l + r)>>1; }
    		inline int len(){return (r - l + 1); }
    		inline void up() {
    			maxx = max(L->maxx , R->maxx);
    	    }
    	}*root;
    	
    	inline void build(RR node *&k, RR int l, RR int r)
    	{
    		k =new node(l, r);
    		if(l == r) 	{
    			k->maxx = num[l];
    			return ;
    		}
    		int mid = k->mid();
    		build(k->L, k->l, mid);
    		build(k->R, mid + 1, r);
    		k->up();
    	}
    	inline void chenge(RR node *k, RR int pos, RR int val)
    	{
    		if(k->l == k->r)
    		{
    			k->maxx = val;
    			return;
    		}
    		int mid = k->mid();
    		if(pos <= mid)chenge(k->L, pos, val);
    		else if(pos >= mid +1 )chenge(k->R, pos, val);
    		k->up();
    	}
    	inline int ask(RR node *k, RR int l, RR int r)
    	{
    		if(l<= k->l && r >= k->r)
    			return k->maxx;
    		int res = 0;
    		int mid = k->mid();
    		if(l <= mid) res = max(res, ask(k->L, l, r));
    		if(r >= mid + 1) res = max(res, ask(k->R, l, r));
    		return res;
    	}
    }tr2;
    // ODT
    struct block
    {
    	int l, r;
        mutable int col;
        block(int l , int r = -1, int col =0) : l(l), r(r), col(col) {}
        friend bool operator < (const block &a, const block &b)
        {
        	return a.l < b.l;
        }
    };
    set< block >s;
    IT split(int pos)
    {
    	IT it = s.lower_bound(block(pos));
    	if(it != s.end() && it->l == pos)
    	  return it;
    	it--;
    	int ll = it->l, rr = it->r;
    	int col = it->col;
    	s.erase( it );
    	s.insert( block(ll, pos - 1, col) );
    	return s.insert( block(pos, rr, col) ).first;
    }
    bool only (IT l, IT r)
    {
    	if(l == r||(++l)--==r)return 1;
    	++l;
    	for(IT i = l; i != r; ++ i)
    	{
    		if(i->r != i->l)return 0;
    	}
    	return 1;
    }
    inline void assign(RR int l, RR int r, RR int col)
    {
    	IT itr = split(r+1), itl = split(l);
    	s.erase(itl, itr);
    	s.insert(block(l, r, col)); 
    }
    /**************************************************************/
    int tmp[N];
    inline int zh_dou(RR int l, RR int r) 
    {
    	int ans = 2e9, rest = c;
    //	memset(tmp, 0, sizeof tmp);
        for(int i = 1; i <= c; i++) tmp[i] = 0;
    	IT itr = split(r+1), itl = split(l), ll, rr;
    	--itl;  ll = rr = itl;
    	while(rr != itr)
    	{
    		if(ll != itl)
    		{
    			--tmp[ll->col];
    			if(!tmp[ll->col]) ++rest;
    		}ll++;
    		while(rest && rr != itr)
    		{
    			++rr; ++tmp[rr->col];
    			if(tmp[rr->col] == 1)  --rest;
    		}
    		if(rr==itr) break;
    		while(!rest && ll!=rr)
    		{
    			--tmp[ll->col];
    			if(!tmp[ll->col])
    			   ++rest;
    			++ll;
    		}
    		if(rest)
    		{
    			--ll;  ++ tmp[ll->col]; --rest;
    		}
    		ans = min(ans, tr1.ask_(ll->r, rr->l)); 
    	} 
    	return  ans == 2e9 ? -1 : ans; 
    }
    inline int w_lj( RR int l, RR int r) 
    {
    //	memset(tmp, 0, sizeof tmp);
        for(int i = 1; i <= c; i++) tmp[i] = 0;
    	int ans = tr2.ask(tr2.root, l, r);
    	IT itr = split(r + 1), itl = split(l), ll, rr;
    	rr = itl; ll = itl;
    	while(rr != itr)
    	{
    		++tmp[rr->col];
    		while(!only(ll, rr))  --tmp[ll->col], ++ll;
    		while(ll!=rr && tmp[rr->col] > 1) --tmp[ll->col], ++ll;
    		if(ll!=rr) ans = max(ans, tr1.ask_(ll->r,  rr->l)); 
    		++rr;
    	}
    	return ans;
    
    }
    signed main()
    {
    	int  l, r, x, y, opt;
    	n = read(); m = read(); c = read();
    	s.insert(block(0, 0, -1)); s.insert(block(n + 1, n + 1, -1));
    	for(RR int i = 1; i <= n; i ++)
    	{
    		num[i] = read();
    		tr1.chenge(i, num[i]);
    	}
    	tr2.build(tr2.root, 1, n);
    	for(RR int i = 1; i <=n; i ++)
    	{
    		int color = read();
    		s.insert(block(i, i, color));
    	}
    	while(m --> 0)
    	{
    		opt = read();
    		if(opt == 1)
    		{
    			x = read(); y = read();
    			tr1.chenge(x, y - tr1.ask_(x, x));
    			tr2.chenge(tr2.root, x, y);
    		}
    		else if(opt == 2)
    		{
    			l = read(); r = read(); x = read();
    			assign(l, r, x);
    		}
    		else if(opt == 3)
    		{
    			l = read(); r = read();
    			int ans = zh_dou(l, r);
    			printf("%d\n", ans);
    		}
    		else 
    		{
    			l = read(); r = read();
    			int ans = w_lj(l, r);
    			printf("%d\n",ans);
    		}	
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Java注解学习
    微信小程序开发的一些基础知识点
    feign请求传送实体类参数的一些摸索
    springcloud bus中踩过的坑
    API网关初接触
    ELKF学习(Elasticsearch+logstash+kibana+filebeat)
    getWriter() has already been called for this response异常的一些问题
    kafka的学习
    如何优化一个丑陋的switch语句!
    项目启动之后进行一些初始化的方法
  • 原文地址:https://www.cnblogs.com/spbv587/p/11552586.html
Copyright © 2011-2022 走看看