珂朵莉树

珂朵莉树(老司机树)

别人的博客。。
看别人博客学的,链接在上面。
算法比较暴力,应该都看得懂
主要用set实现

一般什么时候用?

推平一段区间(把区间里的数变为一个数)
数据随机(数据水)哈哈哈哈哈哈哈

具体实现

存的东西
mutable :可变的,
set中的东西只能读不能改。
但是加上这个也可以改。
因为不知道这个,ce的我快崩溃了

struct Node
{
	int l,r;//区间
	mutable ll v;//值
	Node(int lp,int rr = -1,ll vv = 0):l(lp),r(rr),v(vv){};//初始化
	bool operator < (const Node& a) const//set 比较符
	{
		return l < a.l;
	}
};
set<Node> ss;

核心:
split:

set<Node>::iterator split(int pos)// 把一个区间分开。 返回值是这个点在哪个区间里。
{
	set<Node>::iterator it = ss.lower_bound(Node(pos));
	if(it != ss.end() && it->l == pos)
	{
		return it;
	}
	-- it;
	int l = it->l;
	int r = it->r;
	ll v = it->v;
	ss.erase(it);
	ss.insert(Node(l,pos - 1, v));
	return ss.insert(Node(pos,r,v)).first;
	//s.insert 返回值为一个pair类型 pair<iterator,bool> 第一个是迭代器 是插入的位置。
}

推平一段区间

void change(int l,int r,ll num)//把l到r区间上的值 变为 num
{
	set<Node>::iterator it = split(r + 1);//必须先声明这个
	set<Node>::iterator it2 = split(l);
	ss.erase(it2,it);// 删除set中it到it2里的所有区间。 里面的参数是两个迭代器。
	ss.insert(Node(l,r,num));
}

其他的暴力就好。
例题:
CF896C Willem, Chtholly and Seniorious
操作:
1 l r x : l~r 加 x
2 l r x:l~r变为x
3 l r x:找l~r第x大的数
4 l r x y:求l~r 区间的x幂次和对y取模

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <cmath>
#include <set>
#include <cstring>
#include <string>
#include <bitset>
using namespace std;
typedef long long ll;
typedef pair<int,ll> pii;
const int inf = 0x3f3f3f3f;
#define st first
#define	sd second
#define mkp make_pair
#define pb push_back
ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a % b);}
// int findx(int x){return  x== fa[x] ? x : fa[x] = findx(fa[x]);}
struct cmp
{
	bool operator()(const pii & a, const pii & b)
	{
		return a.second > b.second;
	}
};
const int maxn = 2e5+5;
const ll M = 1e9+7;
ll a[maxn];
int n, m;
ll seed, mod;
ll rd()
{
    ll ret = seed;
    seed = (seed * 7 + 13) % M;
    return ret;
}
struct Node
{
	int l,r;
	mutable ll v;
	Node(int lp,int rr = -1,ll vv = 0):l(lp),r(rr),v(vv){};
	bool operator < (const Node& a) const
	{
		return l < a.l;
	}
};
set<Node> ss;
set<Node>::iterator split(int pos)// 把一个区间分开。 返回值是这个点在哪个区间里。
{
	set<Node>::iterator it = ss.lower_bound(Node(pos));
	if(it != ss.end() && it->l == pos)
	{
		return it;
	}
	-- it;
	int l = it->l;
	int r = it->r;
	ll v = it->v;
	ss.erase(it);
	ss.insert(Node(l,pos - 1, v));
	return ss.insert(Node(pos,r,v)).first;
	//s.insert 返回值为一个pair类型 pair<iterator,bool> 第一个是迭代器 是插入的位置。
}
void change(int l,int r,ll num)//把l到r区间上的值 变为 num
{
	set<Node>::iterator it = split(r + 1);//必须先声明这个
	set<Node>::iterator it2 = split(l);
	ss.erase(it2,it);// 删除set中it到it2里的所有区间。 里面的参数是两个迭代器。
	ss.insert(Node(l,r,num));
}
void add(int l,int r,ll num)//把l到r区间上的值 加 num
{
	
	set<Node>::iterator itr = split(r + 1);必须先声明这个
	set<Node>::iterator itl = split(l);
	for (; itl != itr; ++itl) 
        itl->v += num;
}

bool cmp(pii a,pii b)
{
	return a.sd < b.sd;
}
ll find_k(int l,int r,int k)// 求l~r区间的第k大的数
{
	std::vector<pii> vv;
	set<Node>::iterator itr = split(r + 1);必须先声明这个
	set<Node>::iterator itl = split(l);
	
	while(itl != itr)
	{
		vv.pb(mkp(itl->r - itl->l +  1,itl->v));
		itl ++ ;
	}
	sort(vv.begin(),vv.end(),cmp);
	int s =0 ;
	for (int i = 0; i < vv.size(); i ++ )
	{
		s += vv[i].st;
		if(s >= k)
			return vv[i].sd;
	}
	return -1;
}
ll power(ll a,ll b,ll m)
{
	a %= m;
	ll ans = 1;
	while(b)
	{
		if(b & 1)
		{
			ans = ans * a % m;
		}
		a = a * a % m;
		b >>= 1; 
	}
	return ans;
}
ll gets(int l,int r,ll a,ll b)
{
	
	set<Node>::iterator itr = split(r + 1);必须先声明这个
	set<Node>::iterator itl = split(l);
	ll ans = 0;
	for (; itl != itr; itl ++ )
	{
		ans = (ans + (itl->r - itl->l + 1) * power(itl->v,a,b) % b) % b;
	}
	return ans;
}
int main()
{
	scanf("%d%d%lld%lld",&n,&m,&seed,&mod);
	for (int i = 1; i <= n; i ++ )
	{
		a[i] = (rd() % mod) + 1;
		ss.insert(Node(i,i,a[i]));
	}
	ss.insert(Node(n + 1,n + 1,0));
	while(m -- )
	{
		int f = rd() % 4 + 1;
		int l = (rd() % n) + 1;
		int r = (rd() % n) + 1;
		if(l > r)
			swap(l,r);
		int x,y;
		if(f == 1)
		{
			x = (rd() % mod) + 1;
			add(l,r,x);
		}
		else if(f == 2)
		{
			x = (rd() % mod) + 1;
			change(l,r,x);
		}
		else if(f == 3)
		{
			x = (rd() % (r - l + 1)) + 1;
			ll s = find_k(l,r,x);
			printf("%lld\n",s);
		}
		else
		{
			x = (rd() % mod) + 1;
			y = (rd() % mod) + 1;
			ll ans = gets(l,r,x,y);
			printf("%lld\n",ans % y);
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值