P3835 【模板】可持久化平衡树
版版题。
P3835 【模板】可持久化平衡树
// code by fhq_treap
#include<bits/stdc++.h>
#define ll long long
#define N 500005
inline ll read(){
char C=getchar();
ll A=0 , F=1;
while(('0' > C || C > '9') && (C != '-')) C=getchar();
if(C == '-') F=-1 , C=getchar();
while('0' <= C && C <= '9') A=(A << 1)+(A << 3)+(C - 48) , C=getchar();
return A*F;
}
template <typename T>
void write(T x)
{
if(x < 0) {
putchar('-');
x = -x;
}
if(x > 9)
write(x/10);
putchar(x % 10 + '0');
return;
}
struct P{
int l,r;
int siz,rnd,v;
}T[N * 50];
#define ls(x) T[x].l
#define rs(x) T[x].r
#define s(x) T[x].siz
#define c(x) T[x].rnd
#define v(x) T[x].v
inline void up(int x){s(x) = s(ls(x)) + s(rs(x)) + 1;}
int cnt;
inline int newn(int x){return v(++cnt) = x,c(cnt) = rand(),s(cnt) = 1,cnt;}
#define update up
inline int merge(int x,int y){
if(!x || !y)return x ^ y;
if(c(x) > c(y)){//持久化
int p = ++ cnt;
T[p] = T[x];
rs(p) = merge(rs(p),y);
return up(p),p;
}else{
int p = ++ cnt;
T[p] = T[y];
ls(p) = merge(x,ls(p));
return up(p),p;
}
}
inline void split(int now,int k,int &x,int &y){
if(!now)return void(x = y = 0);
else{
if(v(now) <= k){
x = ++cnt;
T[x] = T[now];
split(rs(x),k,rs(x),y);
up(x);
}else{
y = ++cnt;
T[y] = T[now];
split(ls(y),k,x,ls(y));
up(y);
}
}
}
inline void del(int &root,int w){
int x,y,z;x = y = z = 0;
split(root,w,x,z);
split(x,w - 1,x,y);
y = merge(ls(y),rs(y));
root = merge(merge(x,y),z);
}
inline void ins(int &root,int w){
int x,y,z;x = y = z = 0;
split(root,w,x,y);
z = newn(w);
root = merge(merge(x,z),y);
}
inline int getval(int k,int w){
if(w == s(ls(k)) + 1)return v(k);
else if(w <= s(ls(k)))return getval(ls(k),w);
else return getval(rs(k),w - s(ls(k)) - 1);
}
inline int getkth(int &root,int w){
int x,y;
split(root,w - 1,x,y);
int ans = s(x) + 1;
root = merge(x,y);
return ans;
}
inline int getpre(int &root,int w){
int x,y;
split(root,w - 1,x,y);
if(!x)return -2147483647;
int ans = getval(x,s(x));
root = merge(x,y);
return ans;
}
inline int getnex(int &root,int w){
int x,y,ans;
split(root,w,x,y);
if(!y)return 2147483647;
else ans=getval(y,1);
root=merge(x,y);
return ans;
}
int rt[N];
int n,w,las,f;
int main(){
srand(time(0));
scanf("%d",&n);
for(int i = 1;i <= n;++i){
scanf("%d%d%d",&las,&f,&w);
rt[i] = rt[las];
if(f == 1)ins(rt[i],w);
if(f == 2)del(rt[i],w);
if(f == 3)std::cout<<getkth(rt[i],w)<<"\n";
if(f == 4)std::cout<<getval(rt[i],w)<<"\n";
if(f == 5)std::cout<<getpre(rt[i],w)<<"\n";
if(f == 6)std::cout<<getnex(rt[i],w)<<"\n";
}
}
CF1340F Nastya and CBS
考虑用分块维护块内的合并结果。
若能成功合并则最后的结果一定为若干右括号加上若干左括号。
考虑块间合并时不使用hash,发现题解区有老哥使用了暴力合并的方法。
CF1340F Nastya and CBS
/// code by fhq_treap
#include<bits/stdc++.h>
#define ll long long
#define N 100005
inline ll read(){
char C=getchar();
ll A=0 , F=1;
while(('0' > C || C > '9') && (C != '-')) C=getchar();
if(C == '-') F=-1 , C=getchar();
while('0' <= C && C <= '9') A=(A << 1)+(A << 3)+(C - 48) , C=getchar();
return A*F;
}
template <typename T>
void write(T x)
{
if(x < 0) {
putchar('-');
x = -x;
}
if(x > 9)
write(x/10);
putchar(x % 10 + '0');
return;
}
bool begin;
#define S 350
int n,k,m;
int a[N];
int B;
int in[N],li[N],ri[N];
int L[S][S],R[S][S];//合并结果
int ma[N];//匹配结果
int stk[N],top;
inline void up(int x){
// std::cout<<"DEL BLOCK"<<x<<" "<<li[x]<<" "<<ri[x]<<std::endl;
ma[x] = 1,L[x][0] = R[x][0] = 0,top = 0;
for(int i = li[x];i <= ri[x];++i){
if(a[i] > 0)
stk[++top] = a[i];
else
{
if(top > 0){
if(stk[top -- ] != -a[i]){
ma[x] = 0;
break;
}
}else{
L[x][++L[x][0]] = a[i];
}
}
}
memcpy(R[x] + 1,stk + 1,top * sizeof(int));
R[x][0] = top;
// if(!ma[x])std::cout<<"FUCK\n"<<std::endl;
// else{
// std::cout<<"the Left of Right match"<<"\n";
// std::cout<<L[x][0]<<std::endl;
// for(int i = 1;i <= L[x][0];++i)
// std::cout<<L[x][i]<<" ";
// puts("");
// std::cout<<"the Right of Left match"<<"\n";
// std::cout<<R[x][0]<<std::endl;
// for(int i = 1;i <= R[x][0];++i)
// std::cout<<R[x][i]<<" ";
// puts("");
// puts("");
// }
}
inline void init(){
B = sqrt(n);
// std::cout<<B<<std::endl;
for(int i = 1;i <= n;++i)
in[i] = (i - 1) / B + 1,li[i] = n + 1,ri[i] = 0;
for(int i = 1;i <= n;++i)
li[in[i]] = std::min(i,li[in[i]]),ri[in[i]] = std::max(ri[in[i]],i);
for(int i = 1;i <= in[n];++i)
up(i);
}
inline bool ask(int l,int r){
top = 0;
if(in[l] == in[r]){
for(int i = l;i <= r;++i){
if(a[i] > 0)
stk[++top] = a[i];
else
if(!top || stk[top -- ] != -a[i])
return 0;
}
return !top;
}
for(int i = l;i <= ri[in[l]];++i)
if(a[i] > 0) stk[++top] = a[i];
else if(!top || stk[top -- ] != -a[i]) return 0;
// puts("THE MID BLOCK");
for(int i = in[l] + 1;i <= in[r] - 1;++i){
if(!ma[i])return 0;
if(top < L[i][0])return 0;
for(int j = 1;j <= L[i][0];++j){;
if(!top || stk[top -- ] != -L[i][j])
return 0;
}
memcpy(stk + 1 + top,R[i] + 1,R[i][0] * sizeof(int)),top += R[i][0];
}
for(int i = li[in[r]];i <= r;++i)
if(a[i] > 0) stk[++top] = a[i];
else if(!top || stk[top -- ] != -a[i]) return 0;
return !top;
}
bool end;
int main(){
// std::cout<<(&end - &begin) / 1024 / 1024;
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;++i)
a[i] = read();
init();
int m = read();
while(m -- ){
int opt = read(),x = read(),y = read();
if(opt == 1){
a[x] = y;
up(in[x]);
}else{
puts(ask(x,y) ? "Yes" : "No");
}
}
}
P7561 [JOISC 2021 Day2] 道路の建設案
考虑曼哈顿转切比雪夫\((x,y) -> (x + y,x - y)\),然后二分,发现变成了这个二维数点,我们直接扫描线。
P2824 [HEOI2016/TJOI2016]排序
考虑二分,按大小处理出01串,然后把排序变成区间赋值即可。
P2824 [HEOI2016/TJOI2016]排序
// Problem: P2824 [HEOI2016/TJOI2016]排序
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2824
// Memory Limit: 256 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define N 100005
ll t[N << 2],num[N],tag[N];//维护1的数量
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
#define mid ((l + r) >> 1)
ll n,m,p;
struct P{
ll l,r,opt;
}q[N];
inline void up(int u){
t[u] = t[ls(u)] + t[rs(u)];
}
inline void build(int u,int l,int r,int x){
if(l == r){
t[u] = num[l] >= x;
return;
}
build(ls(u),l,mid,x);
build(rs(u),mid + 1,r,x);
up(u);
}
inline void del(int u,int len){
if(tag[u] == 1){
t[u] = 0;
return;
}
if(tag[u] == 2){
t[u] = len;
return ;
}
}
inline void down(int u,int l,int r){
if(tag[u]){
tag[ls(u)] = tag[u];
tag[rs(u)] = tag[u];
del(ls(u),mid - l + 1);
del(rs(u),r - mid);
tag[u] = 0;
}
}
inline void change(int u,int l,int r,int tl,int tr,int to){
if(tl > tr)
return;
if(tl <= l && r <= tr){
tag[u] = to;
del(u,r - l + 1);
return;
}
down(u,l,r);
if(tl <= mid)
change(ls(u),l,mid,tl,tr,to);
if(tr > mid)
change(rs(u),mid + 1,r,tl,tr,to);
up(u);
return;
}
inline ll que(int u,int l,int r,int tl,int tr){
if(tl <= l && r <= tr)
return t[u];
ll ans = 0;
down(u,l,r);
if(tl <= mid)
ans += que(ls(u),l,mid,tl,tr);
if(tr > mid)
ans += que(rs(u),mid + 1,r,tl,tr);
return ans;
}
//1 2 5 6 3 4
//1 2 6 5 4 3
//1 2 5
inline bool check(int x){
std::memset(tag,0,sizeof(tag));
std::memset(t,0,sizeof(t));
build(1,1,n,x);
for(int i = 1;i <= m;++i){
ll cnt = que(1,1,n,q[i].l,q[i].r);
if(q[i].opt == 1){//降序
change(1,1,n,q[i].l,q[i].l + cnt - 1,2);//1
change(1,1,n,q[i].l + cnt,q[i].r,1);
}else{
cnt = q[i].r - q[i].l + 1 - cnt;
change(1,1,n,q[i].l,q[i].l + cnt - 1,1);//1
change(1,1,n,q[i].l + cnt,q[i].r,2);
}
}
return que(1,1,n,p,p);
}
int main(){
scanf("%lld%lld",&n,&m);
for(int i = 1;i <= n;++i)
scanf("%lld",&num[i]);
for(int i = 1;i <= m;++i)
scanf("%lld%lld%lld",&q[i].opt,&q[i].l,&q[i].r);
scanf("%lld",&p);
ll l = 1,r = n;
ll ans = 0;
while(l + 1 <= r){
if(check(mid))
ans = mid,l = mid + 1;
else
r = mid - 1;
}
while(check(ans + 1))
ans = ans + 1;
std::cout<<ans<<std::endl;
}
P7834 [ONTAK2010] Peaks 加强版
考虑使用Kruskal重构树。
然后可以转为查询子树内第\(k\)大点权叶子,可以对\(dfn\)序维护主席树,或者直接线段树合并都可以。
P7834 [ONTAK2010] Peaks 加强版
#include<bits/stdc++.h>
#define ll long long
#define N 500005
struct P{
int x,y,v;
}e[N];
bool operator < (P a,P b){
return a.v < b.v;
}
int f[N];
int n,m;
inline int find(int x){return (x == f[x] ? x : f[x] = find(f[x]));}
int las = 0;
struct Seg{
int l,r;
ll siz;
}T[N * 20];
ll a[N];
int pcnt;
using std::vector;
vector<int>A[N];
int fa[N][30];
int dfn[N],end[N],inv[N];
int dfncnt;
inline void dfs(int u,int fi){
fa[u][0] = fi;
dfn[u] = end[u] = ++dfncnt;
// std::cout<<u<<" "<<dfn[u]<<std::endl;
inv[dfn[u]] = u;
for(int i = 1;i <= 20;++i)
fa[u][i] = fa[fa[u][i - 1]][i - 1];
for(int i = 0;i < A[u].size();++i){
int v = A[u][i];
dfs(v,u);
end[u] = std::max(end[u],end[v]);
}
}
int head[N];
#define s(x) T[x].siz
#define ls(x) T[x].l
#define rs(x) T[x].r
#define mid ((l + r) >> 1)
int segcnt;
inline void change(int las,int &now,int l,int r,int k){
if(!now) now = ++segcnt;
// std::cout<<las<<" "<<now<<" "<<l<<" "<<r<<" "<<k<<std::endl;
T[now] = T[las];
s(now) ++ ;
if(l == r)return ;
if(k <= mid){
ls(now) = 0;
change(ls(las),ls(now),l,mid,k);
}else{
rs(now) = 0;
change(rs(las),rs(now),mid + 1,r,k);
}
}
int q;
#define inf 1000000005
inline int query(int las,int now,int l,int r,int k){
// std::cout<<las<<" "<<now<<" "<<l<<" "<<r<<" "<<k<<std::endl;
if(s(now) - s(las) < k)
return -1;
if(l == r)return l;
if(s(rs(now)) - s(rs(las)) >= k)
return query(rs(las),rs(now),mid + 1,r,k);
else
return query(ls(las),ls(now),l,mid,k - (s(rs(now)) - s(rs(las))));
}
int main(){
// freopen("q.out","w",stdout);
scanf("%d%d%d",&n,&m,&q);
for(int i = 1;i <= n;++i)
scanf("%d",&a[i]),f[i] = i;
for(int i = 1;i <= 2 * n;++i)
f[i] = i;
for(int i = 1;i <= m;++i)
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v);
std::sort(e + 1,e + m + 1);
pcnt = n;
for(int i = 1;i <= m;++i){
int x = e[i].x,y = e[i].y;
int fx = find(x),fy = find(y);
// std::cout<<"("<<e[i].x<<" "<<e[i].y<<" "<<e[i].v<<" "<<fx<<" "<<fy<<")"<<std::endl;
if(fx != fy){
a[++pcnt] = e[i].v;
// std::cout<<pcnt<<" "<<fx<<std::endl;
// std::cout<<pcnt<<" "<<fy<<std::endl;
A[pcnt].push_back(fx);
A[pcnt].push_back(fy);
f[fx] = pcnt,f[fy] = pcnt;
}
}
dfs(pcnt,0);
for(int i = 1;i <= dfncnt;++i){
// std::cout<<"DEL "<<i<<" "<<inv[i]<<"\n";
if(inv[i] <= n){
change(head[i - 1],head[i],1,inf,a[inv[i]]);
}else{
head[i] = head[i - 1];
}
}
a[0] = inf * 100ll;
int las = 0;
while(q -- ){
int u,x,k;
scanf("%d%d%d",&u,&x,&k);
if(las == -1)las = 0;
u ^= las,x ^= las,k ^= las;
u = (u % n) + 1,k = (k % n) + 1;
// std::cout<<u<<" "<<x<<" "<<k<<std::endl;
for(int i = 20;i >= 0;--i){
if(a[fa[u][i]] <= x)
u = fa[u][i];
}
// std::cout<<u<<std::endl;
std::cout<<(las = query(head[dfn[u] - 1],head[end[u]],1,inf,k))<<"\n";
}
}
/*
10 11 3
1 2 3 4 5 6 7 8 9 10
1 4 4
2 5 3
9 8 2
7 8 10
7 1 4
6 7 1
6 4 8
2 1 5
10 8 10
3 4 7
3 4 6
0 5 5
1 6 8
7 8 1
*/