省选集训杂题乱写

碎碎念

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

闲的没事的时候写的,别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<mx\le 2\times x\),那么将\(x+1\sim mx\)的数合并到\(1\sim x\)上(就是减\(x\))。
  2. \(mx > 2\times x\),那么将\(1\sim x\)统一加\(x\),并打上整块减标记。

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

证明

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

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

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

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

剩下的就和第一分块一样,发现本题卡空间,但是块与块之间没有关联,且答案可加,将询问离线逐块处理即可。总的时间复杂度\(O(n\sqrt 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 = 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是显然的。

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

  1. \(l\le x\le r\)
  2. \(\exists son_{x_1},son_{x_2},l\le son_{x_1},son_{x_2}\le r\)

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

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

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

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

总时间复杂度\(O(n\log^2 n + n\log 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;
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\)以后,要么不变,要么至少除以二。一眼势能线段树,那么就变成了快速判断一个区间内是否有和\(x\)\(gcd\)以后值变小的。

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

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

时间复杂度\(O(n\log n\log V)\)

虽然但是还是没有理解对\(2^{32}\)取模为什么会有人用 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(n\log 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 = 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(n\log^2 n)\),树剖常数小,即使加上一个平衡树也随便过。

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');
    }
  }
}

\(to\; be\; continued\)

posted @ 2024-12-26 20:21  CuFeO4  阅读(39)  评论(0)    收藏  举报