省选集训杂题乱写

碎碎念

不去做专题做这个是吧?😓

闲的没事的时候写的,别D【叠甲】。

所以有人解释一下我的fhq合并为什么T了嘛?(详见 Nauuo and Bug 这道题)

没啥意义的就不放里面了。

「ALFR Round 3」C 割

贪心,发现最后的答案为/k+sth.的形式,最后那一点单调栈维护即可。

code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
auto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
const int N = 2e5 + 10;
int n,k;char s[N];
set<int> st[27];
signed main(){
srand(time(0));
cin.tie(nullptr)->sync_with_stdio(false);
cin>>n>>k>>(s+1);
rep(i,1,n,1) st[s[i]-'a'+1].insert(i);
drep(i,26,1,1){
if(!st[i].size()) continue;
if(k > st[i].size()) cout<<(char)(i-1+'a')<<'\n',exit(0);
else{
int len = st[i].size();
int num = ceil(1.0*len/k);
rep(j,1,num,1) cout<<(char)(i-1+'a');
if(len % k != 0) return 0;
vector<char> sta;
for(int j = *st[i].rbegin() + 1;j <= n; ++j){
while(sta.size() && sta.back() < s[j]) sta.pop_back();
sta.push_back(s[j]);
}
for(auto i:sta) cout<<i;
exit(0);
}
}
}

[Ynoi2018] 五彩斑斓的世界

第二分块,均摊复杂度挺有意思的,剩下的和第一分块没啥区别啊,我调了大概3小时就过了。

发现每块的最大值总是不增的,考虑如何让这个复杂度均摊。假设当前块的最大值为mx,当前操作为整块减x,那么分为两种。

  1. x<mx2×x,那么将x+1mx的数合并到1x上(就是减x)。
  2. mx>2×x,那么将1x统一加x,并打上整块减标记。

合并的话和第一分块一样,并查集维护即可。

证明

考虑证明这个复杂度,下面直接令并查集的复杂度为常数了。

对于第一种操作,我们用了O(mxx)的时间使得最大值减了mxx

对于第二种操作,我们用了O(mx)的时间使得最大值减了x

由于最大值单调,所以总的时间复杂度均摊为O(V)

剩下的就和第一分块一样,发现本题卡空间,但是块与块之间没有关联,且答案可加,将询问离线逐块处理即可。总的时间复杂度O(nn)

code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
auto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
const int N = 1e6 + 10,M = 5e5 + 10,SN = 1010,VN = 1e5 + 10,V = 1e5 + 1,inf = 0x3f3f3f3f;
int n,m,a[N],L[SN],R[SN],len,siz;
int rt[VN],sz[VN],ans[M];
struct Query{int id,l,r,x;}q[M];
struct DSU{
vector<int> fa;
void init(int n){fa.resize(n+1);rep(i,1,n,1) fa[i] = i;}
int get_fa(int x){while(x ^ fa[x]) x = fa[x] = fa[fa[x]];return x;}
void Merge(int x,int y){
x = get_fa(x);y = get_fa(y);
if(x == y) return ;
if(x < y) swap(x,y);fa[x] = y;
}
}D;
void Merge(int x,int y){
if(rt[y]) D.Merge(rt[x],rt[y]),a[D.get_fa(rt[x])] = y,rt[y] = D.get_fa(rt[y]);
else rt[y] = rt[x],a[rt[y]] = y;
sz[y] += sz[x];rt[x] = sz[x] = 0;
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cin>>n>>m;rep(i,1,n,1) cin>>a[i];
rep(i,1,m,1) cin>>q[i].id>>q[i].l>>q[i].r>>q[i].x;
D.init(n);len = sqrt(n);siz = n / len;
rep(i,1,siz,1) L[i] = R[i - 1] + 1,R[i] = i*len;
if(R[siz] < n) siz++,L[siz] = R[siz-1] + 1,R[siz] = n;
rep(now,1,siz,1){
int mx = 0,tag = 0;
memset(rt,0,sizeof rt);memset(sz,0,sizeof sz);
int sl = L[now],sr = R[now];
rep(i,sl,sr,1){
int x = a[i];mx = max(mx,x);
if(!rt[x]) rt[x] = i; else D.fa[i] = rt[x];
sz[x]++;
}
auto upd = [&](int x){
if(mx-tag > x*2){
drep(i,tag+x,tag+1,1) if(rt[i]) Merge(i,i+x);
tag += x;
}
else{
drep(i,mx,tag+x+1,1) if(rt[i]) Merge(i,i-x);
mx = min(mx,tag + x);
}
};
auto rbuild = [&](int l,int r,int x){
rep(i,sl,sr,1) a[i] = a[D.get_fa(i)];
rep(i,sl,sr,1) rt[a[i]] = 0,sz[a[i]] = 0;
rep(i,l,r,1) if(a[i] - tag > x) a[i] -= x;
rep(i,sl,sr,1) rt[a[i]] = 0,sz[a[i]] = 0;
mx = 0;
rep(i,sl,sr,1){
int x = a[i];
mx = max(mx,x);
if(!rt[x]) rt[x] = i,D.fa[i] = i;
else D.fa[i] = rt[x];
sz[x]++;
}
};
rep(i,1,m,1){
auto [id,l,r,x] = q[i];
if(r < sl || l > sr) continue;
if(id == 1){
if(mx - tag <= x) continue;
if(l <= sl && r >= sr) upd(x);
else rbuild(max(l,sl),min(r,sr),x);
}
else{
if(l <= sl && r >= sr) ans[i] += sz[x+tag];
else
rep(now,max(l,sl),min(r,sr),1) if(a[D.get_fa(now)]-tag == x) ans[i]++;
}
}
}
rep(i,1,m,1) if(q[i].id == 2) cout<<ans[i]<<'\n';
}

牛场围栏

同余最短路板子,注意不要重复建边。

code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
auto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
const int N = 3010;
int n,m,x[N],mn = 0x3f3f3f3f;
vector<pair<int,int> > e[N];
set<int> used;
bitset<N> vis;
ll dist[N];
void dijkstra(int s){
memset(dist,0x3f,sizeof dist);
priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;
q.emplace(0,0);dist[0] = 0;
while(q.size()){
int x = q.top().second;q.pop();
if(vis[x]) continue;
vis[x] = true;
for(auto [y,w]:e[x]){
if(dist[y] > dist[x] + w){
dist[y] = dist[x] + w;
q.emplace(dist[y],y);
}
}
}
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cin>>n>>m;
rep(i,1,n,1){cin>>x[i];if(x[i] <= m + 1) cout<<-1,exit(0);mn = min(mn,x[i]);}
mn -= m;
rep(i,1,n,1) rep(j,x[i]-m,x[i],1){
if(j == mn || used.count(j)) continue;
used.insert(j);
rep(k,0,mn-1,1) e[k].emplace_back((k+j)%mn,j);
}
dijkstra(0);
ll ans = 0;
rep(i,0,mn-1,1){
// cerr<<dist[i]<<' ';
if(dist[i] == 0x3f3f3f3f3f3f3f3f) cout<<-1,exit(0);
ans = max(ans,dist[i]-mn);
}
cout<<ans<<'\n';
}

[Ynoi2006] rldcot

枚举LCA是显然的。

假如depx对一个区间[l,r]有贡献,那分为三种情况。

  1. lxr
  2. sonx1,sonx2,lsonx1,sonx2r

对于第二个条件,假如(a,d),(b,c)均为满足条件的点对,且a<b<c<d,那么选(b,c)肯定比选(a,d)优,因为能选(b,c)的一定可以选(a,d),反之不成立。

那么,贪心的,可以得出一个结论,讨论一个点u的贡献时,我们倾向于在它子树内找两个有极近关系(前驱后继)的点。

统计一个节点子树的问题,考虑DSU On Tree,用一个set维护重儿子的节点,然后遍历轻儿子,将轻儿子子树内的每个节点先找出前驱后继,然后再将其插入,可以保证不重不漏,时间复杂度O(nlog2n)

接下来的操作就是离线+扫描线了,depx可能重复,考虑离散化后按照上面贪心的思路统计答案即可。

总时间复杂度O(nlog2n+nlogn)

输入输出比较大,加上快读快写。

code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
auto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
namespace IO{
#ifdef LOCAL
FILE*Fin(fopen("in.in","r")),*Fout(fopen("out.out","w"));
#else
FILE*Fin(stdin),*Fout(stdout);
#endif
class qistream{static const size_t SIZE=1<<26,BLOCK=64;FILE*fp;char buf[SIZE];int p;public:qistream(FILE*_fp=stdin):fp(_fp),p(0){fread_unlocked(buf+p,1,SIZE-p,fp);}void flush(){memmove(buf,buf+p,SIZE-p),fread_unlocked(buf+SIZE-p,1,p,fp),p=0;}qistream&operator>>(char&str){str=getch();while(isspace(str))str=getch();return*this;}template<class T>qistream&operator>>(T&x){x=0;p+BLOCK>=SIZE?flush():void();bool flag=false;for(;!isdigit(buf[p]);++p)flag=buf[p]=='-';for(;isdigit(buf[p]);++p)x=x*10+buf[p]-'0';x=flag?-x:x;return*this;}char getch(){return buf[p++];}qistream&operator>>(char*str){char ch=getch();while(ch<=' ')ch=getch();for(int i=0;ch>' ';++i,ch=getch())str[i]=ch;return*this;}}qcin(Fin);
class qostream{static const size_t SIZE=1<<26,BLOCK=64;FILE*fp;char buf[SIZE];int p;public:qostream(FILE*_fp=stdout):fp(_fp),p(0){}~qostream(){fwrite_unlocked(buf,1,p,fp);}void flush(){fwrite_unlocked(buf,1,p,fp),p=0;}template<class T>qostream&operator<<(T x){int len=0;p+BLOCK>=SIZE?flush():void();x<0?(x=-x,buf[p++]='-'):0;do buf[p+len]=x%10+'0',x/=10,++len;while(x);for(int i=0,j=len-1;i<j;++i,--j)swap(buf[p+i],buf[p+j]);p+=len;return*this;}qostream&operator<<(char x){putch(x);return*this;}void putch(char ch){p+BLOCK>=SIZE?flush():void();buf[p++]=ch;}qostream&operator<<(char*str){for(int i=0;str[i];++i)putch(str[i]);return*this;}}qcout(Fout);
}using namespace IO;
#define cin qcin
#define cout qcout
const int N = 1e5 + 10;
struct BIT{
int mx,t[N];
int lb(int x){return (x&(-x));}
void upd(int pos,int val){rep(i,pos,mx,lb(i)) t[i] += val;}
int qry(int pos){int res = 0;drep(i,pos,1,lb(i)) res += t[i];return res;}
}bit;
struct Point{
int l,val;
Point(){}Point(int L,int V):l(L),val(V){}
};vector<Point> vec[N];
struct Po{int l,r;Po(int L = 0,int R = 0):l(L),r(R){}}ct[N];
vector<pair<int,int> > e[N],q[N];set<int> st;
int n,m,siz[N],son[N],fa[N],ans[N*5];ll dist[N];
void dfs1(int x){
siz[x] = 1;
for(auto [y,w]:e[x]){
if(y == fa[x]) continue;
dist[y] = dist[x] + w;fa[y] = x;
dfs1(y);siz[x] += siz[y];
if(siz[son[x]] < siz[y]) son[x] = y;
}
}
int hugeson;
void Del(int x){
st.erase(x);
for(auto [y,w]:e[x]) if(y != fa[x]) Del(y);
}
void Add(int x){
st.insert(x);
for(auto [y,w]:e[x]) if(y != fa[x]) Add(y);
}
void Ins(int x,int f){
auto it = st.insert(x).first;
if(it != st.begin()){
it--;
int a = *it,b = x;
if(a > b) swap(a,b);
vec[b].emplace_back(a,dist[f]);
it++;
}
it++;
if(it != st.end()){
int a = *it,b = x;
if(a > b) swap(a,b);
vec[b].emplace_back(a,dist[f]);
}
st.erase(x);
for(auto [y,w]:e[x]) if(y != fa[x]) Ins(y,f);
}
void dfs(int x){
vec[x].emplace_back(x,dist[x]);
for(auto [y,w]:e[x]){
if(y == fa[x] || y == son[x]) continue;
dfs(y);Del(y);
}
if(!son[x]) return st.insert(x),void();
dfs(son[x]);
for(auto [y,w]:e[x]){
if(y == fa[x] || y == son[x]) continue;
Ins(y,x);Add(y);
}
st.insert(x);
}
signed main(){
// cin.tie(nullptr)->sync_with_stdio(false);
cin>>n>>m;bit.mx = n;
rep(i,2,n,1){
int u,v,w;cin>>u>>v>>w;
e[u].emplace_back(v,w);e[v].emplace_back(u,w);
}
rep(i,1,m,1){int l,r;cin>>l>>r;q[r].emplace_back(l-1,i);}
rep(i,1,n,1) sort(q[i].begin(),q[i].end());
dfs1(1);
vector<ll> num;
rep(i,1,n,1) num.emplace_back(dist[i]);
num.emplace_back(-0x3f3f3f3f3f3f3f3f);
sort(num.begin(),num.end());num.erase(unique(num.begin(),num.end()),num.end());
rep(i,1,n,1) dist[i] = lower_bound(num.begin(),num.end(),dist[i]) - num.begin();
dfs(1);
rep(now,1,n,1){
for(auto [l,val]:vec[now]){
if(!ct[val].l) ct[val] = Po(l,now),bit.upd(l,1);
else{
if(l < ct[val].l) continue;
bit.upd(ct[val].l,-1);
bit.upd(l,1);ct[val] = Po(l,now);
}
}
int res = bit.qry(now);
for(auto [l,id]:q[now]){
ans[id] += res;
ans[id] -= bit.qry(l);
}
}
rep(i,1,m,1) cout<<ans[i]<<'\n';
}

[Ynoi Easy Round 2023] TEST_69

考虑一个数取gcd以后,要么不变,要么至少除以二。一眼势能线段树,那么就变成了快速判断一个区间内是否有和xgcd以后值变小的。

其实就是快速判断区间内是否所有的数都是x的约数,考虑lcm,如果xmodlcm=0,那么说明区间内所有数都是x的约数,直接跳过即可。

但是值域很大,lcm也可能很大,要打高精嘛?显然如果lcm>1e18,那么xmodlcm一定不为0,直接记为inf或-1即可。

时间复杂度O(nlognlogV)

虽然但是还是没有理解对232取模为什么会有人用 long long存,详见这篇讨论

code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
auto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
using i128 = __int128_t;
const int N = 2e5 + 10;const ll V = 1e18;
int n,m;ull a[N];
i128 gcd(i128 a,i128 b){return b==0?a:gcd(b,a%b);}
i128 LCM(i128 a, i128 b){
if(a == -1 || b == -1) return -1;
i128 gd = gcd(a,b),lm = a/gd*b;
if(lm > V) return -1;
return lm;
}
struct Segment_Tree{
struct segment_tree{int l,r;i128 lcm;unsigned sum;}t[N<<2];
#define l(x) t[x].l
#define r(x) t[x].r
#define lcm(x) t[x].lcm
#define sum(x) t[x].sum
void P(int k){
int ls = k<<1,rs = k<<1|1;
lcm(k) = LCM(lcm(ls),lcm(rs));
sum(k) = sum(ls) + sum(rs);
}
void B(int k,int l,int r){
l(k) = l,r(k) = r;
if(l == r) return sum(k) = lcm(k) = a[l],void();
int mid = (l + r) >> 1;
B(k<<1,l,mid);B(k<<1|1,mid+1,r);P(k);
}
void upd(int k,int l,int r,i128 val){
if(lcm(k) != -1 && val%lcm(k) == 0) return;
if(l(k) == r(k)) return sum(k) = lcm(k) = gcd(lcm(k),val),void();
int mid = (l(k) + r(k)) >> 1;
if(l <= mid) upd(k<<1,l,r,val);
if(r > mid) upd(k<<1|1,l,r,val);
P(k);
}
unsigned qry(int k,int l,int r){
if(l <= l(k) && r(k) <= r) return sum(k);
int mid = (l(k) + r(k)) >> 1;unsigned res = 0;
if(l <= mid) res += qry(k<<1,l,r);
if(r > mid) res += qry(k<<1|1,l,r);
return res;
}
}sgt;
signed main(){
cin>>n>>m;rep(i,1,n,1) cin>>a[i];sgt.B(1,1,n);
rep(test,1,m,1){
int op,l,r;ll val;
cin>>op>>l>>r;
if(op == 1) cin>>val,sgt.upd(1,l,r,val);
else cout<<sgt.qry(1,l,r)<<'\n';
}
}

Nauuo and Bug

这不板子吗,这也配*3300?

函数复合+值域有交线段树合并。

但是正常写fhq合并在值域很小的时候TLE了,有人能解释一下嘛。

这两篇代码唯一的区别在 Join函数中。

TLE On V is small
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
auto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
#define int ll
const int N = 1e6 + 10;
int n,m,p,a[N],tid[N],ans[N],st[N];
vector<int> Ad[N],De[N];
struct FHQ_Treap{
struct node{
int ls,rs,siz,fa,pri;ll val,lz;
node(int L,int R,int S,int F,ll V,int P,ll Z):
ls(L),rs(R),siz(S),fa(F),val(V),pri(P),lz(Z){};
};vector<node> t;
#define ls(x) t[x].ls
#define rs(x) t[x].rs
#define siz(x) t[x].siz
#define fa(x) t[x].fa
#define val(x) t[x].val
#define pri(x) t[x].pri
#define lz(x) t[x].lz
#define eb emplace_back
int tot,rt;
FHQ_Treap(){tot = 0,rt = 0;t.eb(0,0,0,0,0,0,0);}
int New(int val){t.eb(0,0,1,0,val,rand(),0);tot++;return tot;}
void P(int p){
siz(p) = siz(ls(p)) + siz(rs(p)) + 1;
fa(p) = 0;
if(ls(p)) fa(ls(p)) = p;
if(rs(p)) fa(rs(p)) = p;
}
void mk(int p,ll val){if(!p) return;val(p) += val;lz(p) += val;}
void D(int p){if(lz(p)) mk(ls(p),lz(p)),mk(rs(p),lz(p)),lz(p) = 0;}
void split(int p,int val,int &x,int &y){
if(!p) return x = y = 0,void();D(p);
if(val(p) <= val) x = p,split(rs(p),val,rs(x),y);
else y = p,split(ls(p),val,x,ls(y));P(p);
}
int Merge(int x,int y){
if(!x || !y) return x|y;
if(pri(x) < pri(y)) return D(x),rs(x) = Merge(rs(x),y),P(x),x;
else return D(y),ls(y) = Merge(x,ls(y)),P(y),y;
}
int Join(int x,int y){
if(!x || !y) return x|y;
D(x);D(y);
if(pri(x) > pri(y)) swap(x,y);
int a,b;split(y,val(x),a,b);
ls(x) = Join(ls(x),a);
rs(x) = Join(rs(x),b);
return P(x),x;
}
int Insert(int val){
int x,y;split(rt,val,x,y);
int id = New(val);
rt = Merge(Merge(x,id),y);
return id;
}
ll get(int id){
int num = 0;
for(;st[++num] = id;id = fa(id));
for(;num;D(st[num--]));
return val(st[1]);
}
void upd(int val){
int x,y;mk(rt,val);split(rt,p-1,x,y);mk(y,-p);rt = Join(x,y);
}
#undef ls
#undef rs
#undef siz
#undef fa
#undef val
#undef pri
#undef lz
#undef eb
}fhq;
pair<int,int> qry[N];
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
srand(time(0));
cin>>n>>m>>p;rep(i,1,n,1) cin>>a[i];
rep(i,1,m,1){
int l,r;cin>>l>>r;
Ad[l].emplace_back(i);
De[r].emplace_back(i);
}
rep(i,1,n,1){
for(auto id:Ad[i]) tid[id] = fhq.Insert(0);
fhq.upd(a[i]);
for(auto id:De[i]) ans[id] = fhq.get(tid[id]);
}
rep(i,1,m,1) cout<<ans[i]<<'\n';
}
AC code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
auto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
#define int ll
const int N = 2e6 + 10;
int n,m,p,a[N],tid[N],ans[N],st[N];
vector<int> Ad[N],De[N];
mt19937 rnd(24320);
struct FHQ_Treap{
struct node{
int ls,rs,siz,fa,pri;ll val,lz;
node(int L,int R,int S,int F,ll V,int P,ll Z):
ls(L),rs(R),siz(S),fa(F),val(V),pri(P),lz(Z){};
};vector<node> t;
#define ls(x) t[x].ls
#define rs(x) t[x].rs
#define siz(x) t[x].siz
#define fa(x) t[x].fa
#define val(x) t[x].val
#define pri(x) t[x].pri
#define lz(x) t[x].lz
#define eb emplace_back
int tot,rt;
FHQ_Treap(){tot = 0,rt = 0;t.eb(0,0,0,0,0,0,0);}
int New(int val){t.eb(0,0,1,0,val,rand(),0);tot++;return tot;}
void P(int p){
siz(p) = siz(ls(p)) + siz(rs(p)) + 1;fa(p) = 0;
if(ls(p)) fa(ls(p)) = p;if(rs(p)) fa(rs(p)) = p;
}
void mk(int p,ll val){if(!p) return;val(p) += val;lz(p) += val;}
void D(int p){if(lz(p)) mk(ls(p),lz(p)),mk(rs(p),lz(p)),lz(p) = 0;}
void split(int p,int val,int &x,int &y){
if(!p) return x = y = 0,void();D(p);
if(val(p) <= val) x = p,split(rs(p),val,rs(x),y);
else y = p,split(ls(p),val,x,ls(y));P(p);
}
int Merge(int x,int y){
if(!x || !y) return x|y;
if(pri(x) < pri(y)) return D(x),rs(x) = Merge(rs(x),y),P(x),x;
else return D(y),ls(y) = Merge(x,ls(y)),P(y),y;
}
int Join(int x,int y){
if(!x || !y) return x|y;
int rt = 0,a;
while(y){
a = y,D(a);
while(ls(a)) a = ls(a),D(a);
split(x,val(a),a,x);
rt = Merge(rt,a);
swap(x,y);
}
rt = Merge(rt,x);
return rt;
}
int Insert(int val){
int x,y,id;split(rt,val,x,y);
id = New(val),rt = Merge(Merge(x,id),y);
return id;
}
ll get(int id){
int num = 0;for(;st[++num] = id;id = fa(id));
for(;num;D(st[num--]));return val(st[1]);
}
void upd(int val){
int x,y;mk(rt,val);split(rt,p-1,x,y);mk(y,-p);rt = Join(x,y);
}
#undef ls
#undef rs
#undef siz
#undef fa
#undef val
#undef pri
#undef lz
#undef eb
}fhq;
pair<int,int> qry[N];
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
srand(time(0));
cin>>n>>m>>p;rep(i,1,n,1) cin>>a[i];
rep(i,1,m,1){
int l,r;cin>>l>>r;
Ad[l].emplace_back(i);
De[r].emplace_back(i);
}
rep(i,1,n,1){
for(auto id:Ad[i]) tid[id] = fhq.Insert(0);
fhq.upd(a[i]);
for(auto id:De[i]) ans[id] = fhq.get(tid[id]);
}
rep(i,1,m,1) cout<<ans[i]<<'\n';
}

Special Segments of Permutation

以区间最大值为分治中心分治,启发式合并即可。

时间复杂度O(nlogn)

code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
auto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
const int N = 2e5 + 10;
int n,a[N],lg[N],ct[N];ll ans = 0;
pair<int,int> st[18][N];
int qry(int l,int r){int k = lg[r-l+1];return max(st[k][l],st[k][r-(1<<k)+1]).second;}
void work(int l,int r,bool keep){
if(l > r) return;
if(l == r){if(keep) ct[a[l]]++;return;}
int mid = qry(l,r),mx = a[mid];
int len1 = mid-l,len2 = r-mid;
if(len1 > len2) work(mid+1,r,false),work(l,mid-1,true);
else work(l,mid-1,false),work(mid+1,r,true);
if(len1 > len2) rep(i,mid+1,r,1) ans += ct[mx-a[i]];
else rep(i,l,mid-1,1) ans += ct[mx-a[i]];
if(!keep){
if(len1 > len2) rep(i,l,mid-1,1) ct[a[i]]--;
else rep(i,mid+1,r,1) ct[a[i]]--;
}
else{
ct[mx]++;
if(len1 > len2) rep(i,mid+1,r,1) ct[a[i]]++;
else rep(i,l,mid-1,1) ct[a[i]]++;
}
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cin>>n;rep(i,1,n,1) cin>>a[i],st[0][i] = {a[i],i};
rep(i,2,n,1) lg[i] = lg[i >> 1] + 1;
rep(j,1,lg[n],1) rep(i,1,n-(1<<j)+1,1)
st[j][i] = max(st[j-1][i],st[j-1][i+(1<<(j-1))]);
work(1,n,false);
cout<<ans<<'\n';
}

[Ynoi2011] ODT

Ynoi最水的一集。

套路的,将树进行重链剖分,然后对于每个节点维护一颗平衡树,维护其轻儿子的点权。

时间复杂度O(nlog2n),树剖常数小,即使加上一个平衡树也随便过。

code
#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
auto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
namespace IO{
#define gc getchar_unlocked
#define pc putchar_unlocked
struct IO{
template<class T>
inline void read(T &x){
char s = gc();x = 0;
for(;s < '0' || s > '9';s = gc());
for(;'0' <= s && s <= '9';s = gc())
x = (x<<1)+(x<<3)+(s^48);
}
template<class T,class... Args>
inline void read(T &x,Args&... argc){read(x);read(argc...);}
template<class T>
inline void write(T x){
static int sta[30],top;top = 0;
do sta[++top] = x%10;while(x /= 10);
while(top) pc(sta[top--]+'0');
}
inline void write(char x){pc(x);}
template<class T,class... Args>
inline void write(T x,Args... argc){write(x);write(argc...);}
}io;
}using IO::io;
#define read io.read
#define write io.write
#define pii pair<int,int>
#define mk make_pair
const int N = 1e6 + 10;
int n,m,a[N],top[N],siz[N],son[N],fa[N],dep[N],dfn[N],rdfn[N],tim;
vector<int> e[N];
tree<pii,null_type,less<pii>,rb_tree_tag,tree_order_statistics_node_update> bst[N];
void dfs1(int x){
dep[x] = dep[fa[x]] + 1;
siz[x] = 1;
for(auto y:e[x]){
if(y == fa[x]) continue;
fa[y] = x;dfs1(y);
siz[x] += siz[y];
if(siz[son[x]] < siz[y]) son[x] = y;
}
}
void dfs2(int x,int t){
top[x] = t;rdfn[dfn[x] = ++tim] = x;
if(son[x]) dfs2(son[x],t);else return;
for(auto y:e[x]){
if(y == fa[x] || y == son[x]) continue;
bst[x].insert(mk(a[y],y));dfs2(y,y);
}
}
struct BIT{
int mx,t[N];int lb(int x){return (x&(-x));}
void upd(int pos,int val){rep(i,pos,mx,lb(i)) t[i] += val;}
void upd(int l,int r,int val){upd(l,val);upd(r+1,-val);}
int qry(int pos){int res = 0;drep(i,pos,1,lb(i)) res += t[i];return res;}
}bit;
void upd(int x,int y,int val){
if(!val) return;
int fx = top[x],fy = top[y];
while(fx ^ fy){
if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy);
int rx = x;
x = fa[fx];
bst[x].erase(mk(a[fx] + bit.qry(dfn[fx]),fx));
bit.upd(dfn[fx],dfn[rx],val);
bst[x].insert(mk(a[fx] + bit.qry(dfn[fx]),fx));
fx = top[x];
}
if(dep[x] > dep[y]) swap(x,y);
if(x == top[x] && fa[x]){
fx = x;
x = fa[fx];
bst[x].erase(mk(a[fx] + bit.qry(dfn[fx]),fx));
bit.upd(dfn[fx],dfn[y],val);
bst[x].insert(mk(a[fx] + bit.qry(dfn[fx]),fx));
}
else bit.upd(dfn[x],dfn[y],val);
}
int qry(int x,int k){
int q1 = bit.qry(dfn[x]),q2 = bit.qry(dfn[fa[x]]),q3 = bit.qry(dfn[son[x]]);
bst[x].insert(mk(a[x]+q1,x));
if(fa[x]) bst[x].insert(mk(a[fa[x]]+q2,fa[x]));
if(son[x]) bst[x].insert(mk(a[son[x]]+q3,son[x]));
int res = (*bst[x].find_by_order(k-1)).first;
//for(auto [val,id]:bst[x]) cerr<<val<<' '<<id<<'\n';
bst[x].erase(mk(a[x]+q1,x));
if(fa[x]) bst[x].erase(mk(a[fa[x]]+q2,fa[x]));
if(son[x]) bst[x].erase(mk(a[son[x]]+q3,son[x]));
return res;
}
signed main(){
read(n,m);rep(i,1,n,1) read(a[i]);
rep(i,2,n,1){int u,v;read(u,v);e[u].emplace_back(v);e[v].emplace_back(u);}
dfs1(1);dfs2(1,1);bit.mx = n;
rep(test,1,m,1){
int op,x,y,z;
read(op,x,y);
if(op == 1){
read(z);upd(x,y,z);
}
else{
write(qry(x,y),'\n');
}
}
}

tobecontinued

posted @   CuFeO4  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示