珂朵莉树(老司机树)
别人的博客。。
看别人博客学的,链接在上面。
算法比较暴力,应该都看得懂
主要用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);
}
}
}