个人acm模板整理

1.数学

1.1.普通lucas

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+100;
ll a[N];
ll p;
ll pow(ll y,ll z,ll p){
    y%=p;ll ans=1;
    for(ll i=z;i;i>>=1,y=y*y%p) if(i&1) ans=ans*y%p;
    return ans;
}
ll C(ll n,ll m){
    if(m>n) return 0;
    return ((a[n]*pow(a[m],p-2,p))%p*pow(a[n-m],p-2,p)%p);
}
ll lucas(ll n,ll m){
    if(!m) return 1;
    return C(n%p,m%p)*lucas(n/p,m/p)%p;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int t;cin>>t;
    while(t--){
        ll n,m;
        cin>>n>>m>>p;
        a[0]=1;
        for(int i=1;i<=p;i++) a[i]=(a[i-1]*i)%p;
        cout<<lucas(n+m,n)<<endl;
    }
}

扩展卢卡斯定理/exLucas

#include<bits/stdc++.h>
#define ll long long
using namespace std;
#ifndef Fading
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
#endif
#ifdef Fading
#define gc getchar
#endif
void exgcd(ll a,ll b,ll &x,ll &y){
    if (!b) return (void)(x=1,y=0);
    exgcd(b,a%b,x,y);
    ll tmp=x;x=y;y=tmp-a/b*y;
}
ll gcd(ll a,ll b){
    if (b==0) return a;
    return gcd(b,a%b); 
}
inline ll INV(ll a,ll p){
    ll x,y;
    exgcd(a,p,x,y);
    return (x+p)%p;
}
inline ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline ll mabs(ll x){
    return (x>0?x:-x);
}
inline ll fast_mul(ll a,ll b,ll p){
    ll t=0;a%=p;b%=p;
    while (b){
        if (b&1LL) t=(t+a)%p;
        b>>=1LL;a=(a+a)%p;
    }
    return t;
}
inline ll fast_pow(ll a,ll b,ll p){
    ll t=1;a%=p;
    while (b){
        if (b&1LL) t=(t*a)%p;
        b>>=1LL;a=(a*a)%p;
    }
    return t;
}
inline ll read(){
    ll x=0,f=1;char ch=gc();
    while (!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while (isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
inline ll F(ll n,ll P,ll PK){
    if (n==0) return 1;
    ll rou=1;//循环节
    ll rem=1;//余项 
    for (ll i=1;i<=PK;i++){
        if (i%P) rou=rou*i%PK;
    }
    rou=fast_pow(rou,n/PK,PK);
    for (ll i=PK*(n/PK);i<=n;i++){
        if (i%P) rem=rem*(i%PK)%PK;
    }
    return F(n/P,P,PK)*rou%PK*rem%PK;
}
inline ll G(ll n,ll P){
    if (n<P) return 0;
    return G(n/P,P)+(n/P);
}
inline ll C_PK(ll n,ll m,ll P,ll PK){
    ll fz=F(n,P,PK),fm1=INV(F(m,P,PK),PK),fm2=INV(F(n-m,P,PK),PK);
    ll mi=fast_pow(P,G(n,P)-G(m,P)-G(n-m,P),PK);
    return fz*fm1%PK*fm2%PK*mi%PK;
}
ll A[1001],B[1001];
//x=B(mod A)
inline ll exLucas(ll n,ll m,ll P){
    ll ljc=P,tot=0;
    for (ll tmp=2;tmp*tmp<=P;tmp++){
        if (!(ljc%tmp)){
            ll PK=1;
            while (!(ljc%tmp)){
                PK*=tmp;ljc/=tmp;
            }
            A[++tot]=PK;B[tot]=C_PK(n,m,tmp,PK);
        }
    }
    if (ljc!=1){
        A[++tot]=ljc;B[tot]=C_PK(n,m,ljc,ljc);
    }
    ll ans=0;
    for (ll i=1;i<=tot;i++){
        ll M=P/A[i],T=INV(M,A[i]);
        ans=(ans+B[i]*M%P*T%P)%P;
    }
    return ans;
}
signed main(){
    ll n=read(),m=read(),P=read();
    printf("%lld\n",exLucas(n,m,P));
    return 0;
}

1.2扩展中国剩余定理(EXCRT)

#include<bits/stdc++.h>
using namespace std;
typedef __int128 ll;
ll ext_gcd(ll a,ll b,ll &x,ll &y){
    ll t,d;
    if(b==0){x=1;y=0;return a;}
    d=ext_gcd(b,a%b,x,y);
    t=x;
    x=y;
    y=t-a/b*y;
    return d;
}
ll Invmod(ll a,ll n){
    ll x,y;
    if(ext_gcd(a,n,x,y)!=1) return -1;
    return (x%n+n)%n;
}
bool mergef(ll b1,ll c1,ll b2,ll c2,ll &b,ll &c){
    ll tb1=b1,tb2=b2;
    c=((c2-c1)%b2+b2)%b2;
    ll g=__gcd(b1,b2);
    if(c%g) return false;
    c/=g;
    b1/=g;
    b2/=g;
    c=c*Invmod(b1,b2)%b2;
    c=c*tb1+c1;
	b=tb1*tb2/g;
    c%=b;
    return true;
}
ll merge(long long b[],long long c[],int n){
    ll bb=b[0],cc=c[0],bbb,ccc;
    ll i;
    for(i=1;i<n;i++){
        if(!mergef(bb,cc,b[i],c[i],bbb,ccc))
            return -1;
            bb=bbb;
            cc=ccc;
    }
    return cc;
}

const int N=1e5+10;
long long ww[N],bb[N];
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>ww[i]>>bb[i];
    cout<<(long long)merge(ww,bb,n);


}

1.3模数原根表

模数原根表
常用素数:
P = 1004535809  ====>  pr = 3
P = 998244353  =====>  pr = 3

//(g 是mod(r*2^k+1)的原根)
 
素数  r  k  g
3   1   1   2
5   1   2   2
17  1   4   3
97  3   5   5
193 3   6   5
257 1   8   3
7681    15  9   17
12289   3   12  11
40961   5   13  3
65537   1   16  3
786433  3   18  10
5767169 11  19  3
7340033 7   20  3
23068673    11  21  3
104857601   25  22  3
167772161   5   25  3
469762049   7   26  3
1004535809  479 21  3
2013265921  15  27  31
2281701377  17  27  3
3221225473  3   30  5
75161927681 35  31  3
77309411329 9   33  7
206158430209    3   36  22
2061584302081   15  37  7
2748779069441   5   39  3
6597069766657   3   41  5
39582418599937  9   42  5
79164837199873  9   43  5
263882790666241 15  44  7
1231453023109121    35  45  3
1337006139375617    19  46  3
3799912185593857    27  47  5
4222124650659841    15  48  19
7881299347898369    7   50  6
31525197391593473   7   52  3
180143985094819841  5   55  6
1945555039024054273 27  56  5
4179340454199820289 29  57  3

1.4拓展欧拉定理

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll qpow(ll a,ll b,ll q){
    ll ans=1;
    a%=q;
    while(b){
        if(b&1) ans=(ans*a)%q;
        b>>=1;
        a=a*a%q;
    }
    return ans;
}
int euler(int n){
    int ans=1;
    for(int i=2;i*i<=n;i++){
        if(n%i==0){
            n/=i;
            ans*=i-1;
            while(n%i==0){
                n/=i;
                ans*=i;
            }
        }
    }
    if(n>1) ans*=n-1;
    return ans;
}
int main(){
    ll a,m,bb=0,flag=0;
    string b;
    cin>>a>>m>>b;
    ll phi=euler(m);
    for(int i=0;i<b.length();i++){
        bb*=10;
        bb+=b[i]-'0';
        if(bb>=phi){
            bb%=phi;
            flag=1;
        }
    }
    if(flag==1) bb+=phi;
    cout<<qpow(a,bb,m)<<endl;
}

1.5多项式启发式合并

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
typedef long long ll;
const int N = 1e6+7;
const int mod = 998244353;
ll fac[N];
ll invf[N];
ll qpow(ll x,ll n) {
	ll res = 1;
	while (n) {
		if (n&1) res = res * x % mod;
		x = x * x % mod;
		n >>= 1;
	}
	return res;
}
ll C(int m,int n) {
	return fac[m]*invf[n]%mod*invf[m-n]%mod;
}
namespace Poly {
	#define ck(x) (x>=mod?x-mod:x)
	typedef vector<int> poly;
	const int G = 3;
	const int inv_G = qpow(G,mod-2);
	int RR[N],deer[2][19][N],inv[N];
	void init(const int t) {
		for (int p=1;p<=t;p++) {
			int buf1 = qpow(G,(mod-1)/(1<<p));
			int buf0 = qpow(inv_G,(mod-1)/(1<<p));
			deer[0][p][0] = deer[1][p][0] = 1;
			for (int i=1;i<(1<<p);i++) {
				deer[0][p][i] = 1ll*deer[0][p][i-1]*buf0%mod;
				deer[1][p][i] = 1ll*deer[1][p][i-1]*buf1%mod;
			}
		}
		inv[1] = 1;
		for (int i=2;i<=(1<<t);i++) {
			inv[i] = 1ll*inv[mod%i]*(mod-mod/i)%mod;
		}
	}
	int NTT_init(int n) {
		int limit = 1,L = 0;
		while (limit<=n) limit<<=1,L++;
		for (int i=0;i<limit;++i) {
			RR[i] = (RR[i>>1]>>1|((i&1)<<(L-1)));
		}
		return limit;
	}
	void NTT(poly &A,int type,int limit) {
		A.resize(limit);
		for (int i=0;i<limit;i++) {
			if (i<RR[i]) swap(A[i],A[RR[i]]);
		}
		for (int mid=2,j=1;mid<=limit;mid<<=1,++j) {
			int len = mid>>1;
			for (int pos=0;pos<limit;pos+=mid) {
				int *wn = deer[type][j];
				for (int i=pos;i<pos+len;++i,++wn) {
					int tmp = 1ll*(*wn)*A[i+len]%mod;
					A[i+len] = ck(A[i]-tmp+mod);
					A[i] = ck(A[i]+tmp);
				}
			}
		}
		if (type==0) {
			for (int i=0;i<limit;i++) {
				A[i] = 1ll*A[i]*inv[limit]%mod;
			}
		}
	}
	poly poly_mul(poly A,poly B) {
		int deg = A.size()+B.size()-1;
		int limit = NTT_init(deg);
		poly C(limit);
		NTT(A,1,limit);
		NTT(B,1,limit);
		for (int i=0;i<limit;++i) {
			C[i] = 1ll*A[i]*B[i]%mod;
		}
		NTT(C,0,limit);
		C.resize(deg);
		return C;
	}
}
using namespace Poly;
poly a[N];
typedef pair<int,int> pii;
int main() {
	fac[0] = 1;
	for (int i=1;i<N;i++) fac[i] = fac[i-1]*i%mod;
	invf[N-1] =  qpow(fac[N-1],mod-2);
	for (int i=N-2;i>=0;i--) {
		invf[i] = invf[i+1]*(i+1)%mod;
	}
	init(18);
	int m,k;
	cin>>m>>k;
	a[0].push_back(1);
	for(int i=1,now;i<=m;i++){
		cin>>now;
		a[i].push_back(1);
		a[i].push_back(now);
	}
	priority_queue<pii,vector<pii>,greater<pii>> q;
	for (int i=1;i<=m;i++) {
		q.push({a[i].size(),i});
	}
	while (q.size()>1) {
		int id1 = q.top().se;
		q.pop();
		int id2 = q.top().se;
		q.pop();
		a[id1] = poly_mul(a[id1],a[id2]);
		q.push({a[id1].size(),id1});
	} 
	int id = q.top().se;
	ll tmp = a[id][k];	
	ll tmp2 = k;
	tmp2 = qpow(tmp2,k/2);
	tmp = tmp*qpow(tmp2,mod-2)%mod*qpow(C(m,k),mod-2)%mod;
	cout<<tmp;
}

2.数据结构

2.1线段树合并

#include<bits/stdc++.h>
using namespace std;
const int N=2e5;
const int LOG=40;
vector<int>g[N];
int n,m,q[N],deep[N];
int t,f[N][30];
int root[N*LOG],ma[N*LOG],type[N*LOG],lc[N*LOG],rc[N*LOG],cnt;
#define mid ((l+r)>>1)
void dfs(int rt){
    int hh=0,tt=0;
    q[tt++]=rt;
    deep[rt]=1;
    while(hh!=tt){
        int x=q[hh++];
        if(hh==N) hh=0;
        for(auto y:g[x]){
            if(deep[y]) continue;
            deep[y]=deep[x]+1;
            q[tt++]=y;
            if(tt==N) tt=0;
            f[y][0]=x;
            for(int j=1;j<=t;j++) 
            f[y][j]=f[f[y][j-1]][j-1];
        }
    }
}
int lca(int x,int y){
    if(deep[x]>deep[y]) swap(x,y);
    for(int i=t;i>=0;i--)
        if(deep[f[y][i]]>=deep[x])
            y=f[y][i];
    if(x==y) return x;
    for(int i=t;i>=0;i--) 
        if(f[x][i]!=f[y][i])
        x=f[x][i],y=f[y][i];
    return f[x][0];
}
void pushup(int node){
    ma[node]=max(ma[lc[node]],ma[rc[node]]);
    type[node]=ma[lc[node]]>=ma[rc[node]] ? type[lc[node]]:type[rc[node]];    
}
void update(int &node,int l,int r,int x,int v){
    if(node==0) node=++cnt;
    if(l==r){
        ma[node]+=v;
        type[node]=l;
        return ;
    }
    if(x<=mid) update(lc[node],l,mid,x,v);
    else update(rc[node],mid+1,r,x,v);
    pushup(node);
}
int query(int node){
    return type[node];
}
int merge(int a,int b,int l,int r){
    if(!a||!b) return a+b;
    if(l==r){
        ma[a]=ma[a]+ma[b];
        type[a]=l;
        return a;
    }
    lc[a]=merge(lc[a],lc[b],l,mid);
    rc[a]=merge(rc[a],rc[b],mid+1,r);
    pushup(a);
    return a;
}
int ans[N];
void dfs1(int x,int fa){
    for(auto son:g[x]) {
        if(son==fa) continue;
        dfs1(son,x);
    }
    for(auto son:g[x]){
        if(son==fa) continue;
        root[x]=merge(root[x],root[son],0,N);
    }
    ans[x]=query(root[x]);
}


int main(){
    cin>>n>>m;
    for(int i=1,x,y;i<=n-1;i++){
        cin>>x>>y;
        g[x].push_back(y),g[y].push_back(x);
    }
    g[n+1].push_back(1),g[1].push_back(n+1);
    t=(int)(log(n+1)/log(2))+2;
    dfs(n+1);
    for(int i=1,a,b,z;i<=m;i++){
        cin>>a>>b>>z;
        if(deep[a]>deep[b]) swap(a,b);
        int fa=lca(a,b);
        if(fa==a){
            update(root[f[fa][0]],0,N,z,-1);
            update(root[b],0,N,z,+1);
        }
        else {
            update(root[f[fa][0]],0,N,z,-1);
            update(root[fa],0,N,z,-1);
            update(root[b],0,N,z,+1);
            update(root[a],0,N,z,+1);
        }
    }
    dfs1(n+1,-1);
    for(int i=1;i<=n;i++) cout<<ans[i]<<endl;
    

}

2.2线段树分裂

#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define int long long
const int MAXN=3e5;
const int LOG=30;
int root[MAXN*LOG],sum[MAXN*LOG],lc[MAXN*LOG],rc[MAXN*LOG],cnt;
const int V=3e5;
void pushup(int x){
    sum[x]=sum[lc[x]]+sum[rc[x]];
}
int query(int node,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr) return sum[node];
    int ans=0;
    if(ql<=mid) ans+=query(lc[node],l,mid,ql,qr);
    if(qr>=mid+1) ans+=query(rc[node],mid+1,r,ql,qr);
    return ans;
}
int querykth(int node,int l,int r,int k){
    if(l==r) return l;
    if(sum[lc[node]]>=k) return querykth(lc[node],l,mid,k);
    else return querykth(rc[node],mid+1,r,k-sum[lc[node]]);
}
void update(int &node,int l,int r,int x,int v){
    if(!node) node=++cnt;
    if(l==r){sum[node]+=v;return ;}
    if(x<=mid) update(lc[node],l,mid,x,v);
    else update(rc[node],mid+1,r,x,v);
    pushup(node);
}
int merge(int a,int b,int l,int r){
    if(!a||!b) return a+b;
    if(l==r){
        sum[a]=sum[a]+sum[b];
        return a;
    }
    lc[a]=merge(lc[a],lc[b],l,mid);
    rc[a]=merge(rc[a],rc[b],mid+1,r);
    pushup(a);
    return a;
}
int split(int &a,int b,int ql,int qr,int l,int r){
    if(ql<=l&&r<=qr) {b=a;a=0;return b;}if(!b) b=++cnt;
    if(ql<=mid) lc[b]=split(lc[a],lc[b],ql,qr,l,mid);
    if(qr>mid) rc[b]=split(rc[a],rc[b],ql,qr,mid+1,r);
    pushup(a),pushup(b);return b;
}

int n,m;
int od=1;
signed main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        int now;cin>>now;
        update(root[1],1,V,i,now);
    }
    for(int i=1;i<=m;i++){
        int opt,x,y,p,t,q,k;cin>>opt;
        if(opt==0){
            cin>>p>>x>>y;
            od++;
            root[od]=split(root[p],root[od],x,y,1,V);
        }else if(opt==1){
            cin>>p>>t;
            root[p]=merge(root[p],root[t],1,V);
        }
        else if(opt==2){
            cin>>p>>x>>q;
            update(root[p],1,V,q,x);
        }
        else if(opt==3){
            cin>>p>>x>>y;
            cout<<query(root[p],1,V,x,y)<<endl;;
        }else if(opt==4){
            cin>>p>>k;
            if(sum[root[p]]<k) cout<<-1<<endl;
            else cout<<querykth(root[p],1,V,k)<<endl;
        }
    }

}

2.3splay&&fhq

在这里插入图片描述

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    return x*f;
}
const int N=1e5+100;
const int M=1e6+100;
template<typename T = unsigned int>
class Balanced_Binary_Tree {
private:
    struct Point {
        T value;
        unsigned int count;
        unsigned int size;
        unsigned int daughter[2], mother;
        Point() { size = count = 0, mother = daughter[1] = daughter[0] = 0; }
        Point(T const value) {
            this->value = value,
            size = count = 1, mother = daughter[1] = daughter[0] = 0;
        }
    } tree[N + M + 1];
    unsigned int length, size, root;
    bool inline get_id(unsigned int const x) const {
        return tree[tree[x].mother].daughter[1] == x;
    }
    void const inline upto(unsigned int const x) {
        tree[x].size =
            tree[tree[x].daughter[0]].size + tree[tree[x].daughter[1]].size
            + tree[x].count;
    }
    void const inline connect
        (unsigned int const x, unsigned int const y, bool const id) {
        tree[x].mother = y, tree[y].daughter[id] = x;
    }
    void const inline rotate(unsigned int const x) {
        unsigned int const m(tree[x].mother), g(tree[m].mother);
        bool const id(get_id(x)), mid(get_id(m));
        connect(tree[x].daughter[!id], m, id), upto(m),
        connect(m, x, !id), upto(x), connect(x, g, mid);
    }
    void const inline splay(unsigned int const x, unsigned int root) {
        root = tree[root].mother;
        while (tree[x].mother not_eq root)
            if (tree[tree[x].mother].mother == root) rotate(x);
            else
                if (get_id(x) == get_id(tree[x].mother))
                    rotate(tree[x].mother), rotate(x);
                else
                    rotate(x), rotate(x);
    }
    void const inline Splay(unsigned int const x) {
        splay(x, root), root = x;
    }
public:
    Balanced_Binary_Tree() { size = length = 0; }
    void const inline Insert(T const x) {
        if (not size++) {
            tree[root = ++length] = Point(x), connect(root, 0, 0);
            return;
        }
        for (unsigned int register i(root); ++tree[i].size, true;) {
            if (tree[i].value == x)
                { ++tree[i].count, Splay(i); return; }
            else {
                bool id(tree[i].value < x);
                if (not tree[i].daughter[id]) {
                    tree[++length] = Point(x), connect(length, i , id),
                    Splay(length);
                    return;
                }
                else
                    i = tree[i].daughter[id];
            }
        }
    }
    void const inline Delete(T const x) {
        --size;
        for (
            unsigned int register i(root);
            tree[i].size--;
            i = tree[i].daughter[x > tree[i].value]
        )
            if (tree[i].value == x) {
                if (--tree[i].count) { Splay(i); return; }
                Splay(i);
                if (not tree[i].daughter[0])
                    { connect(root = tree[i].daughter[1], 0, 0); return; }
                if (not tree[i].daughter[1])
                    { connect(root = tree[i].daughter[0], 0, 0); return; }
                unsigned int j(tree[i].daughter[0]);
                while (tree[j].daughter[1]) j = tree[j].daughter[1];
                splay(j, tree[i].daughter[0]);
                connect(tree[i].daughter[1], tree[i].daughter[0], 1),
                upto(tree[i].daughter[0]),
                connect(root = tree[i].daughter[0], 0, 0);
                return;
            }
    }
    unsigned int inline Get_Ranking(T const x) {
        unsigned int r(1);
        for (unsigned int register i(root); i;)
            if (tree[i].value == x)
                { Splay(i); return tree[tree[i].daughter[0]].size + 1; }
            else
                if (tree[i].value < x)
                    r += tree[tree[i].daughter[0]].size + tree[i].count,
                    i = tree[i].daughter[1];
                else
                    i = tree[i].daughter[0];
        return r;
    }
    unsigned int inline Get_Rank(unsigned int const x) {
        unsigned int r(1);
        for (unsigned int register i(root); true;) {
            if (
                r + tree[tree[i].daughter[0]].size <= x
                and x < r + tree[tree[i].daughter[0]].size + tree[i].count
            ) { Splay(i); return tree[i].value; }
            else
                if (x < r + tree[tree[i].daughter[0]].size)
                    i = tree[i].daughter[0];
                else
                    r += tree[tree[i].daughter[0]].size + tree[i].count,
                    i = tree[i].daughter[1];
        }
    }
    T inline Get_Less(T const x) {
        T r; unsigned int register li;
        for (unsigned int register i(root); i;)
            if (tree[i].value >= x) li = i, i = tree[i].daughter[0];
            else r = tree[li = i].value, i = tree[i].daughter[1];
        Splay(li);
        return r;
    }
    T inline Get_Greater(T const x) {
        T r; unsigned int register li;
        for (unsigned int register i(root); i;)
            if (tree[i].value <= x) li = i, i = tree[i].daughter[1];
            else r = tree[li = i].value, i = tree[i].daughter[0];
        Splay(li);
        return r;
    }
};
Balanced_Binary_Tree<int> spl;


int n,m;
int a[N];
int fin;
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
        spl.Insert(a[i]);
    }
    int lastans=0;
    for(int i=1;i<=m;i++){
        int opt=read(),v=read();
        v^=lastans;
        if(opt==1){
            spl.Insert(v);
        }else if(opt==2){
            spl.Delete(v);
        }else if(opt==3){
            int tmp=spl.Get_Ranking(v);
            lastans=tmp;
            fin^=lastans;
        }else if(opt==4){
            int tmp=spl.Get_Rank(v);
            lastans=tmp;
            fin^=lastans;
        }else if(opt==5){
            int tmp=spl.Get_Less(v);
            lastans=tmp;
            fin^=lastans;
        }else if(opt==6){
            int tmp=spl.Get_Greater(v);
            lastans=tmp;
            fin^=lastans;
        }
    }
    cout<<fin<<endl;

}
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cstdlib>
#include<ctime>

using namespace std;
typedef long long ll;
const int N = 500007, M = 5000007, INF = 0x3f3f3f3f;

//num:节点编号
namespace treap{// 无旋treap (fhq-treap)
    const int N = 500007, M = 5000007, INF = 0x3f3f3f3f;

    struct fhq_treap{
        int l, r;
        int size;
        int fa;
        int val, fix;
        ll sum;
    }tr[N];

    int cnt;
    int x, y, z, root;

    inline void pushup(int p)
    {
        tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + 1;
        tr[p].sum = tr[tr[p].l].sum + tr[tr[p].r].sum + tr[p].val;
        tr[tr[p].l].fa = tr[tr[p].r].fa = p;
    }

    inline void split(int p, int k, int &x, int &y)//split_by_val
    {
        if(!p){x = y = 0; return ;}
        if(tr[p].val <= k)x = p, split(tr[p].r, k, tr[p].r, y);
        else y = p, split(tr[p].l, k, x, tr[p].l);
        pushup(p);
    }

    inline int merge(int x, int y)
    {
        if(!x || !y)return x + y;
        if(tr[x].fix > tr[y].fix){//小根堆
           tr[x].r = merge(tr[x].r, y);pushup(x);return x;
        }
        else {
            tr[y].l = merge(x, tr[y].l);pushup(y);return y;
        }
    }

    //!得到新节点
    inline int get_node(int val)
    {
        tr[++ cnt].size = 1;
        tr[cnt].fix = rand();
        tr[cnt].sum = tr[cnt].val = val;
        tr[cnt].fa = 0;
        return cnt;
    }

    //!树中插入新节点
    inline void my_insert(int val)
    {
        split(root, val, x, y);
        root = merge(merge(x, get_node(val)), y);
    }

    //!按值删除所有权值为k的所有点
    inline void my_delet_all(int val)
    {
        split(root, val, x, z);
        split(x, val - 1, x, y);
        root = merge(x, z);
        return ;
    }

    //!按值删除给定权值的一个点
    inline void my_delet_one(int val)
    {
        split(root, val, x, z);
        split(x, val - 1, x, y);
        y = merge(tr[y].l, tr[y].r);
        root = merge(merge(x, y), z);
        return ;
    }

    //!查询指定排名的一个数,返回那个数的编号
    inline int get_num_by_rank(int p, int k)
    {
        while(true){
            if(k <= tr[tr[p].l].size)p = tr[p].l;
            else if(k == tr[tr[p].l].size + 1)return p;
            else k -= tr[tr[p].l].size + 1, p = tr[p].r;
        }
    }

    //!按权值分裂时查询一个数的排名///

    //!根据权值查询一个数的排名
    inline int get_rank_by_val(int val)
    {
        split(root, val - 1, x, y);
        int res = tr[x].size + 1;
        root = merge(x, y);
        return res;
    }

    //!按排名分裂时查询一个数的排名/
    //!需要维护父节点

    //!根据编号查询这个数的排名
    inline int get_rank_by_num(int p)
    {
        int res = tr[tr[p].l].size + 1;
        while(p != root){//一直回溯
            if(p == tr[tr[p].fa].r)res += tr[tr[tr[p].fa].l].size + 1;
            p = tr[p].fa;
        }
        return res;
    }

    inline int get_val_by_rank(int k)
    {
        int res = tr[get_num_by_rank(root, k)].val;
        return res;
    }


    //!查找前驱的编号
    //!按值查找比它小的数中的最大的数的编号
    inline int get_prev_of_num(int val)
    {
        split(root, val - 1, x, y);
        int res = tr[get_num_by_rank(x, tr[x].size)].val;
        root = merge(x, y);
        return res;
    }

    //!查找后继的编号
    //!按值查找比它大的数中最小数的编号
    inline int get_next_of_num(int val)
    {
        split(root, val, x, y);
        int res = tr[get_num_by_rank(y, 1)].val;
        root = merge(x, y);
        return res;
    }

    //!查找节点的祖先节点
    inline int get_anc(int x)
    {
        while(tr[x].fa){
            x = tr[x].fa;
        }
        return x;
    }


    inline void main()
    {
        srand((unsigned)time(NULL));
        memset(tr, 0, sizeof tr);
        cnt = 0;
    }
}

int n, m;

int main()
{
    scanf("%d", &n);
    treap::main();

    while(n -- ){
        int op, x;
        scanf("%d%d", &op, &x);
        if(op == 1)treap::my_insert(x);
        else if(op == 2)treap::my_delet_one(x);
        else if(op == 3)printf("%d\n", treap::get_rank_by_val(x));
        else if(op == 4)printf("%d\n", treap::get_val_by_rank(x));
        else if(op == 5)printf("%d\n", treap::get_prev_of_num(x));
        else if(op == 6)printf("%d\n", treap::get_next_of_num(x));
    }
    return 0;
}

在这里插入图片描述

2.4线段树分治

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=6e5;
#define mid ((l+r)>>1)
#define ls node<<1
#define rs node<<1|1
int n,x,y,z,sz[N],fa[N],top;
ll ans;
vector<pii>d[N],e[N<<2];
int find(int x){
    while(x^fa[x]){
        x=fa[x];
    }
    return x;
}
void update(int node,int l,int r,int ql,int qr,pii pi){
    if(ql<=l&&r<=qr){
        return e[node].push_back(pi),void();
    }
    if(ql<=mid) update(ls,l,mid,ql,qr,pi);
    if(qr>mid)  update(rs,mid+1,r,ql,qr,pi);
}
void solve(int node,int l,int r){
    vector<int>dl;
    for(auto v:e[node]){
        int p=find(v.first),q=find(v.second);
        if(p==q) continue;
        if(sz[p]>sz[q]) swap(p,q);
        dl.push_back(p),sz[q]+=sz[p],fa[p]=q;
    }
    if(l==r){
        for(auto v:d[l])
        ans+=1ll*sz[find(v.first)]*sz[find(v.second)];
    }
    else{
        solve(node<<1,l,mid),solve(node<<1|1,mid+1,r);
    }
    reverse(dl.begin(),dl.end());
    for(auto v:dl) sz[fa[v]]-=sz[v],fa[v]=v;
}




int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<n;i++){
        cin>>x>>y>>z;
        d[z].push_back({x,y});
        if(z>1) update(1,1,n,1,z-1,{x,y});
        if(z<n) update(1,1,n,z+1,n,{x,y});
    }
    for(int i=1;i<=n;i++) sz[fa[i]=i]=1;
    solve(1,1,n);
    // cout<<"here"<<endl;
    cout<<ans<<endl;
    return 0;

}


2.5可持久化线段树

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+100;
const int LOG=35;
const int V=1e9+10;
int sum[N*LOG],lc[N*LOG],rc[N*LOG],root[N*LOG],cnt;
#define mid ((l+r)>>1)
void pushup(int node){
    sum[node]=sum[lc[node]]+sum[rc[node]];
}
void update(int pre,int &node,int l,int r,int x){
    node=++cnt;
    if(l==r) {sum[node]=sum[pre]+1;return ;}
    lc[node]=lc[pre],rc[node]=rc[pre];
    if(x<=mid) update(lc[pre],lc[node],l,mid,x);
    if(x>mid)  update(rc[pre],rc[node],mid+1,r,x);
    pushup(node);
}
int query(int pre,int now,int l,int r,int k){
    if(l==r) return l;
    int lcsz=sum[lc[now]]-sum[lc[pre]];
    if(k<=lcsz) return query(lc[pre],lc[now],l,mid,k);
    else  return query(rc[pre],rc[now],mid+1,r,k-lcsz);
}
int a[N],n,m;
int main(){
    cin>>n>>m;for(int i=1;i<=n;i++) {
        int now;cin>>now;
        update(root[i-1],root[i],0,V,now);
    }
    for(int i=1;i<=m;i++){
        int l,r,k;cin>>l>>r>>k;
        cout<<query(root[l-1],root[r],0,V,k)<<endl;
    }
}

2.6动态开点线段树

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+100;
const int LOG=20;
const int V=1e9+10;
int sum[N*LOG],lc[N*LOG],rc[N*LOG];
int root,cnt;
typedef long long ll;
#define mid ((l+r)>>1)
void pushup(int node){
    sum[node]=sum[lc[node]]+sum[rc[node]];
}

void update(int &node,int l,int r,int x){
    if(node==0) node=++cnt;
    if(l==r){sum[node]++;return;}
    if(x<=mid) update(lc[node],l,mid,x);
    if(x>mid) update(rc[node],mid+1,r,x);
    pushup(node);
}
int query(int node,int l,int r,int ql,int qr){
    if((l>=ql&&r<=qr)||node==0) return sum[node];
    int ans=0;
    if(ql<=mid) ans=ans+query(lc[node],l,mid,ql,qr);
    if(qr>=mid+1) ans=ans+query(rc[node],mid+1,r,ql,qr);
    return ans;
}
ll ans;
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) {
        int now;cin>>now;
        ans+=query(root,1,V,now+1,V);
        // cout<<query(root,1,V,now+1,V)<<"!"<<endl;
        update(root,1,V,now);
    }
    
    cout<<ans<<endl;

}

2.7虚树(Static Query on Tree)

#include<bits/stdc++.h>
using namespace std;
// #pragma GCC optimize(2)
// #pragma G++ optimize(2)
const int N=8e5+100;
typedef long long ll;
typedef pair<int,int> pii;
int dfn[N],dep[N],fa[N][25];
int lst[N],t;
int read() {
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
struct EDGE{
    int to,next;
    ll val;
}edge[N<<1],edge1[N<<1];


int n,q,num,top,dfscnt=1;
int stak[N];


int head[N],cnt=1;
void add(int x,int y,int v=0){
    edge[cnt].next=head[x];
    edge[cnt].to=y;
    edge[cnt].val=v;
    head[x]=cnt++;
}

int head1[N];
int cnt1=1;
void add1(int x,int y,int v=0){
    edge1[cnt1].next=head1[x];
    edge1[cnt1].to=y;
    edge1[cnt1].val=v;
    head1[x]=cnt1++;
}

void dfs(int pos){
    int k;
   for(int j=1;j<=t;j++) fa[pos][j]=fa[fa[pos][j-1]][j-1];
    dfn[pos]=dfscnt++;
    for(int i=head[pos];i;i=edge[i].next){
        int to=edge[i].to;
        if(!dfn[to]){
            dep[to]=dep[pos]+1;
            fa[to][0]=pos;
            dfs(to);
        }
    }
}
int lca(int x,int y){
    if(dep[x]>dep[y]) swap(x,y);
    // cout<<x<<" "<<y<<endl;
    for(int i=t;i>=0;i--){
        if(dep[fa[y][i]]>=dep[x])
            y=fa[y][i];
    }

    if(x==y) return x;
    for(int i=t;i>=0;i--){
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i]; 
    }
    return fa[x][0];
}
int ta[N],tb[N],tc[N];
int dp[N];
int ans;
void dfs1(int x){
    for(int i=head1[x];i;i=edge1[i].next){
        int son=edge1[i].to;
        dfs1(son);
        ta[x]=ta[x]|ta[son];
        tb[x]=tb[x]|tb[son];
        if(ta[son]&&tb[son]){
            dp[x]+=dp[son]+edge1[i].val;
        }
    }
    if(tb[x]&&ta[x]) dp[x]++;
    if(tc[x]){
        ans+=dp[x];
        dp[x]=0;
    }
}
void cle(int x){
    for(int i=head1[x];i;i=edge1[i].next){
        int son=edge1[i].to;
        cle(son);
    }
    ta[x]=tb[x]=tc[x]=0;
    head1[x]=0;
    dp[x]=0;
}



int cal(int x){
    
    ans=0;
    dfs1(x);
    cle(1);
    cnt1=1;
    printf("%d\n",ans);
    return 0;
}


bool cmp(int x1,int x2){
    return dfn[x1]<dfn[x2];
}

void solve(){
    
    int n,q;n=read(),q=read();
    t=(int)(log(n)/log(2))+1;
    cnt=1;
    memset(fa,0,sizeof fa);
    for(int i=1;i<=2*n;i++) dfn[i]=0,dep[i]=0,head[i]=0;
    for(int i=2,r;i<=n;i++) cin>>r,add(r,i);
    dfscnt=1,top=0;
    dep[1]=1;
    dfs(1);
    // cout<<endl;
    while(q--){
        top=0;
        vector<int>v;
        int a,b,c;
        a=read(),b=read(),c=read();
        v.push_back(1);
        for(int i=1,tmp;i<=a;i++) tmp=read(),ta[tmp]=1,v.push_back(tmp);
        for(int i=1,tmp;i<=b;i++) tmp=read(),tb[tmp]=1,v.push_back(tmp);
        for(int i=1,tmp;i<=c;i++) tmp=read(),tc[tmp]=1,v.push_back(tmp);
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());int len=v.size();
        for(int i=0;i<len;i++){
            lst[i+1]=v[i];
        }
        sort(lst+1,lst+1+len,cmp);
        stak[top=1]=lst[1];
        for(int i=2;i<=len;i++){
            int now=lst[i];
            int lc=lca(now,stak[top]);
            while(1)
                if(dep[lc]>=dep[stak[top-1]]){
                    if(lc!=stak[top]){
                        add1(lc,stak[top],dep[stak[top]]-dep[lc]-1);
                        if(lc!=stak[top-1])
                            stak[top]=lc;
                        else top--;
                    }
                    break;
                }
                else {
           add1(stak[top-1],stak[top],dep[stak[top]]-dep[stak[top-1]]-1);
                    top--;
                }
                stak[++top]=now;
        }
        while(--top)
            add1(stak[top],stak[top+1],dep[stak[top+1]]-dep[stak[top]]-1);
            cal(1);
    }

}

int main(){
    int t;t=read();
    while(t--){
        solve();
    }
    
}

2.8分块(蒲公英)

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N=4e4+100;
const int K=220;
int cnt[N];
int L[N],R[N],pos[N],a[N],p[K][K],s[K][N];
// int cnt[N];
int n,m,t;
void init_pre(){
//处理p数组
    for(int i=1;i<=t;i++){
        int ma=-1,id=1e7;
        memset(cnt,0,sizeof cnt);
        for(int ii=L[i];ii<=n;ii++){
            cnt[a[ii]]++;
            if(cnt[a[ii]]>ma||(cnt[a[ii]]==ma&&a[ii]<id)){
                ma=cnt[a[ii]];
                id=a[ii];
            }
            int j=pos[ii];
            p[i][j]=id; 
        }
    }
    for(int i=1;i<=t;i++){
        for(int ii=1;ii<=R[i];ii++){
            s[i][a[ii]]++;
        }
    }
    memset(cnt,0,sizeof cnt);
}
int get_num(int l,int r,int v)//l块到r块中v出现几次
{   
    return s[r][v]-s[l-1][v];
}
vector<int>v;

int get_ans(int l,int r){
    int p1=pos[l],q1=pos[r];
    int ma=-1,id=1e7;
    if(p1==q1){
        for(int i=l;i<=r;i++){
            cnt[a[i]]++;
            if(cnt[a[i]]>ma||(cnt[a[i]]==ma&&a[i]<id)){
                ma=cnt[a[i]];
                id=a[i];
            }
        }   
        for(int i=l;i<=r;i++) cnt[a[i]]--;
        return v[id];
    }
    if(p1+1<=q1-1) id=p[p1+1][q1-1],ma=get_num(p1+1,q1-1,id);
    for(int i=l;i<=R[p1];i++) {
        cnt[a[i]]++;
        if(cnt[a[i]]+get_num(p1+1,q1-1,a[i])>ma||
        (cnt[a[i]]+get_num(p1+1,q1-1,a[i])==ma&&a[i]<id)){
                ma=cnt[a[i]]+get_num(p1+1,q1-1,a[i]);
                id=a[i];
        }
    }
    for(int i=L[q1];i<=r;i++){
        cnt[a[i]]++;
        if(cnt[a[i]]+get_num(p1+1,q1-1,a[i])>ma||
        (cnt[a[i]]+get_num(p1+1,q1-1,a[i])==ma&&a[i]<id)){
                ma=cnt[a[i]]+get_num(p1+1,q1-1,a[i]);
                id=a[i];
        }
    }
    for(int i=l;i<=R[p1];i++) {
        cnt[a[i]]--;
    }
    for(int i=L[q1];i<=r;i++){
        cnt[a[i]]--;
    }

    return v[id];
}   



int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    t=sqrt(n);
    for(int i=1;i<=t;i++){
        L[i]=(i-1)*sqrt(n)+1;
        R[i]=i*sqrt(n);
    }
    if(R[t]<n) t++,L[t]=R[t-1]+1,R[t]=n;
    for(int i=1;i<=t;i++){
        for(int j=L[i];j<=R[i];j++){
            pos[j]=i;
        }
    }
    for(int i=1;i<=n;i++) v.push_back(a[i]);
    sort(v.begin(),v.end());
    for(int i=1;i<=n;i++) 
    a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin();
    init_pre();
    int x=0;
    for(int i=1;i<=m;i++){
        int l0,r0,l,r;cin>>l0>>r0;
        l=((l0+x-1)%n)+1,r=((r0+x-1)%n)+1;
        if(l>r) swap(l,r);
        x=get_ans(l,r);
        cout<<x<<endl;
    }
}

2.9fhq-treap(线段树)

/*平衡树实际上画出来是一颗乱糟糟的小根堆,但是满足小根堆的性质,
所以我们这里区间翻转,找到区间需要按照排名split,
只需要在这个区间里一直交换左右儿子即可实现区间翻转*/
/*最后中序遍历输出值即可*/
#include<bits/stdc++.h>
#define ls tr[p].l
#define rs tr[p].r

using namespace std;
typedef long long ll;
const int N = 100007;

int n, m, root;

namespace treap{

    int n, m, tot;

    struct tree{
        int l, r;
        int fix;
        ll val;
        int size;
        int lz;
        ll sum;
    }tr[100007];

    inline int get_node(int v)
    {
        tr[++ tot].val = v;
        tr[tot].size = 1;
        tr[tot].fix = rand();
        return tot;
    }
    void add(int p,int v){
        tr[p].val+=v,tr[p].lz+=v;
        tr[p].sum+=(tr[ls].size+tr[rs].size+1)*v;
    }
    void pushdown(int p)//下传懒标记,注意先交换,再下传
    {
        if(tr[p].lz){
            if(ls) add(ls,tr[p].lz);
            if(rs) add(rs,tr[p].lz);
            tr[p].lz=0;
        }
    }

    void pushup(int p)
    {
        tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + 1;
        tr[p].sum  =tr[ls].sum+tr[rs].sum+tr[p].val;
    }
    
    void split(int p, int rnk, int &x, int &y)
    {
        if(!p){x = y = 0;return ;}
        pushdown(p);
        //合并左边,往右边走
        if(tr[tr[p].l].size + 1 <= rnk)x = p,split(tr[p].r, rnk - tr[tr[p].l].size - 1, tr[p].r, y);
        else y = p, split(tr[p].l, rnk, x, tr[p].l);
        pushup(p);
    }

    int merge(int x, int y)
    {
        if(!x || !y)return x + y;
        if(tr[tr[x].l].fix < tr[tr[y].l].fix)
        // if(rand()&1)
        {
            pushdown(x);
            tr[x].r = merge(tr[x].r, y);
            pushup(x);
            return x;
        }
        else {
            pushdown(y);
            tr[y].l = merge(x, tr[y].l);
            pushup(y);
            return y;
        }
    }


}

int main()
{
    // scanf("%d%d", &n, &m);
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    srand(time(0));
    cin>>n>>m;
    for(int i = 1; i <= n; ++ i)
    {   
        int now;cin>>now;
        root = treap::merge(root, treap::get_node(now));
    }
    for(int i = 1, l, r, x, y, p,k,opt; i <= m; ++ i)
    {       
        cin>>opt;
        if(opt==1){
            cin>>l>>r>>k;
            treap::split(root, r, x, y);
            treap::split(x, l - 1, x, p);
            treap::add(p,k);
            root = treap::merge(treap::merge(x, p), y);
        }
        else {
            cin>>l>>r;
            treap::split(root, r, x, y);
            treap::split(x, l - 1, x, p);
            cout<<treap::tr[p].sum<<endl;
            root = treap::merge(treap::merge(x, p), y);
        }
        
    }
    return 0;
}


2.10 KD-Tree

在这里插入图片描述

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=200010;
int n,op,xl,xr,yl,yr,lstans;
struct node{
  int x,y,v;
}s[maxn];
bool cmp1(int a,int b){return s[a].x<s[b].x;}
bool cmp2(int a,int b){return s[a].y<s[b].y;}
double a=0.725;
int rt,cur,d[maxn],lc[maxn],rc[maxn],L[maxn],R[maxn];
int D[maxn],U[maxn],siz[maxn],sum[maxn];
int g[maxn],t;
void print(int x){
  if(!x) return;
  print(lc[x]);
  g[++t]=x;
  print(rc[x]);
}
void maintain(int x){
  siz[x]=siz[lc[x]]+siz[rc[x]]+1;
  sum[x]=sum[lc[x]]+sum[rc[x]]+s[x].v;
  L[x]=R[x]=s[x].x;
  D[x]=U[x]=s[x].y;
  if(lc[x])
    L[x]=min(L[x],L[lc[x]]),R[x]=max(R[x],R[lc[x]]),
    D[x]=min(D[x],D[lc[x]]),U[x]=max(U[x],U[lc[x]]);
  if(rc[x])
    L[x]=min(L[x],L[rc[x]]),R[x]=max(R[x],R[rc[x]]),
    D[x]=min(D[x],D[rc[x]]),U[x]=max(U[x],U[rc[x]]);
}
int build(int l,int r){
  if(l>r) return 0;
  int mid=(l+r)>>1;
  double av1=0,av2=0,va1=0,va2=0;
  for(int i=l;i<=r;i++) av1+=s[g[i]].x,av2+=s[g[i]].y;
  av1/=(r-l+1);
  av2/=(r-l+1);
  for(int i=l;i<=r;i++)
    va1+=(av1-s[g[i]].x)*(av1-s[g[i]].x),
    va2+=(av2-s[g[i]].y)*(av2-s[g[i]].y);
  if(va1>va2)
    nth_element(g+l,g+mid,g+r+1,cmp1),d[g[mid]]=1;
  else
    nth_element(g+l,g+mid,g+r+1,cmp2),d[g[mid]]=2;
  lc[g[mid]]=build(l,mid-1);
  rc[g[mid]]=build(mid+1,r);
  maintain(g[mid]);
  return g[mid];
}

void rebuild(int &x){
  t=0;
  print(x);
  x=build(1,t);
}

bool bad(int x){return a*siz[x]<=(double)max(siz[lc[x]],siz[rc[x]]);}
void insert(int &x,int v){
  if(!x){
    x=v;
    maintain(x);
    return ;
  }
  if(d[x]==1){
    if(s[v].x<=s[x].x)
      insert(lc[x],v);
    else 
      insert(rc[x],v);
  }else{
    if(s[v].y<=s[x].y) 
      insert(lc[x],v);
      else 
      insert(rc[x],v);
  }
  maintain(x);
  if(bad(x)) rebuild(x);
}
int query(int x) {
  if (!x || xr < L[x] || xl > R[x] || yr < D[x] || yl > U[x]) return 0;
  if (xl <= L[x] && R[x] <= xr && yl <= D[x] && U[x] <= yr) return sum[x];
  int ret = 0;
  if (xl <= s[x].x && s[x].x <= xr && yl <= s[x].y && s[x].y <= yr)
    ret += s[x].v;
  return query(lc[x]) + query(rc[x]) + ret;
}
int main() {
  scanf("%d", &n);
  while (~scanf("%d", &op)) {
    if (op == 1) {
      cur++, scanf("%d%d%d", &s[cur].x, &s[cur].y, &s[cur].v);
      s[cur].x ^= lstans;
      s[cur].y ^= lstans;
      s[cur].v ^= lstans;
      insert(rt, cur);
    }
    if (op == 2) {
      scanf("%d%d%d%d", &xl, &yl, &xr, &yr);
      xl ^= lstans;
      yl ^= lstans;
      xr ^= lstans;
      yr ^= lstans;
      printf("%d\n", lstans = query(rt));
    }
    if (op == 3) return 0;
  }
}

在这里插入图片描述

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
const int maxn = 200010;
int n, d[maxn], lc[maxn], rc[maxn];
double ans = 2e18;

struct node {
  double x, y;
} s[maxn];

double L[maxn], R[maxn], D[maxn], U[maxn];

double dist(int a, int b) {
  return (s[a].x - s[b].x) * (s[a].x - s[b].x) +
         (s[a].y - s[b].y) * (s[a].y - s[b].y);
}

bool cmp1(node a, node b) { return a.x < b.x; }

bool cmp2(node a, node b) { return a.y < b.y; }

void maintain(int x) {
  L[x] = R[x] = s[x].x;
  D[x] = U[x] = s[x].y;
  if (lc[x])
    L[x] = min(L[x], L[lc[x]]), R[x] = max(R[x], R[lc[x]]),
    D[x] = min(D[x], D[lc[x]]), U[x] = max(U[x], U[lc[x]]);
  if (rc[x])
    L[x] = min(L[x], L[rc[x]]), R[x] = max(R[x], R[rc[x]]),
    D[x] = min(D[x], D[rc[x]]), U[x] = max(U[x], U[rc[x]]);
}

int build(int l, int r) {
  if (l >= r) return 0;
  int mid = (l + r) >> 1;
  double avx = 0, avy = 0, vax = 0, vay = 0;  // average variance
  for (int i = l; i <= r; i++) avx += s[i].x, avy += s[i].y;
  avx /= (double)(r - l + 1);
  avy /= (double)(r - l + 1);
  for (int i = l; i <= r; i++)
    vax += (s[i].x - avx) * (s[i].x - avx),
        vay += (s[i].y - avy) * (s[i].y - avy);
  if (vax >= vay)
    d[mid] = 1, nth_element(s + l, s + mid, s + r + 1, cmp1);
  else
    d[mid] = 2, nth_element(s + l, s + mid, s + r + 1, cmp2);
  lc[mid] = build(l, mid - 1), rc[mid] = build(mid + 1, r);
  maintain(mid);
  return mid;
}

double f(int a, int b) {
  double ret = 0;
  if (L[b] > s[a].x) ret += (L[b] - s[a].x) * (L[b] - s[a].x);
  if (R[b] < s[a].x) ret += (s[a].x - R[b]) * (s[a].x - R[b]);
  if (D[b] > s[a].y) ret += (D[b] - s[a].y) * (D[b] - s[a].y);
  if (U[b] < s[a].y) ret += (s[a].y - U[b]) * (s[a].y - U[b]);
  return ret;
}

void query(int l, int r, int x) {
  if (l > r) return;
  int mid = (l + r) >> 1;
  if (mid != x) ans = min(ans, dist(x, mid));
  if (l == r) return;
  double distl = f(x, lc[mid]), distr = f(x, rc[mid]);
  if (distl < ans && distr < ans) {
    if (distl < distr) {
      query(l, mid - 1, x);
      if (distr < ans) query(mid + 1, r, x);
    } else {
      query(mid + 1, r, x);
      if (distl < ans) query(l, mid - 1, x);
    }
  } else {
    if (distl < ans) query(l, mid - 1, x);
    if (distr < ans) query(mid + 1, r, x);
  }
}

int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) scanf("%lf%lf", &s[i].x, &s[i].y);
  build(1, n);
  for (int i = 1; i <= n; i++) query(1, n, i);
  printf("%.4lf\n", sqrt(ans));
  return 0;
}

2.11dsu on tree

给出一棵节点有颜色的树,每次询问某个节点的子树内有多少种不同的颜色。

#include <cstdio>
#include <cstring>
#define maxn 100010

int n,m,col[maxn];
struct edge{int y,next;};
edge e[maxn*2];
int first[maxn];
void buildroad(int x,int y)
{
	static int len=0;
	e[++len]=(edge){y,first[x]};
	first[x]=len;
}
int size[maxn],mson[maxn];
void dfs1(int x,int fa)//求重儿子
{
	size[x]=1;
	for(int i=first[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(y==fa)continue;
		dfs1(y,x);
		if(size[y]>size[mson[x]])mson[x]=y;
		size[x]+=size[y];
	}
}
int tong[maxn],ans[maxn],now_ans=0;
void go(int x,int fa,int type)
{
	tong[col[x]]+=type;
	if(type==1&&tong[col[x]]==1)now_ans++;
	if(type==-1&&tong[col[x]]==0)now_ans--;
	for(int i=first[x];i;i=e[i].next)
	if(e[i].y!=fa)go(e[i].y,x,type);
}
void dfs2(int x,int fa,bool del)
//求解,del表示求完x的子树的答案后需不需要清空x的子树的信息
{
	for(int i=first[x];i;i=e[i].next)//先统计轻儿子的答案
	if(e[i].y!=fa&&e[i].y!=mson[x])dfs2(e[i].y,x,true);
	if(mson[x]!=0)dfs2(mson[x],x,false);//最后统计重儿子的答案
	
	tong[col[x]]++;if(tong[col[x]]==1)now_ans++;//统计自己以及轻子树的信息
	for(int i=first[x];i;i=e[i].next)
	if(e[i].y!=fa&&e[i].y!=mson[x])go(e[i].y,x,1);
	ans[x]=now_ans;//得到自己的答案
	
	if(del)go(x,fa,-1);//假如要删掉自己的信息,就暴力地删掉
}

int main()
{
	scanf("%d",&n);
	for(int i=1,x,y;i<n;i++)
	scanf("%d %d",&x,&y),buildroad(x,y),buildroad(y,x);
	for(int i=1;i<=n;i++)
	scanf("%d",&col[i]);
	dfs1(1,0);
	dfs2(1,0,false);
	scanf("%d",&m);
	for(int i=1,x;i<=m;i++)
	scanf("%d",&x),printf("%d\n",ans[x]);
}

2.12 可持久化平衡树

在这里插入图片描述

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<queue>
#include<stack>
using namespace std;
#define go(i,j,n,k) for(int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(int i=j;i>=n;i-=k)
#define rep(i,x) for(int i=h[x];i;i=e[i].nxt)
#define mn 500010
#define ld long double
#define fi first
#define se second
#define inf 1<<30
#define ll long long
#define root 1,n,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define bson l,r,rt
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-f;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct edge{
    int ch[2], sze, pri;
    ll w;
} z[mn * 50];
int rot[mn], xx, yy, zz, n, cnt;
inline void update(int rt) {
    z[rt].sze = 1;
    if(z[rt].ch[0]) z[rt].sze += z[z[rt].ch[0]].sze;
    if(z[rt].ch[1]) z[rt].sze += z[z[rt].ch[1]].sze;
} 
inline int newnode(ll w = 0) {
    z[++cnt].w = w;
    z[cnt].sze = 1;
    z[cnt].pri = rand();
    return cnt;
}
inline int merge(int x, int y) {
    if(!x || !y) return x + y;
    if(z[x].pri < z[y].pri) {
        int rt = newnode();
        z[rt] = z[x];
        z[rt].ch[1] = merge(z[rt].ch[1], y);
        update(rt);
        return rt;
    } else {
        int rt = newnode();
        z[rt] = z[y];
        z[rt].ch[0] = merge(x, z[rt].ch[0]);
        update(rt);
        return rt;
    }
}
inline void split(int rt, ll k, int &x, int &y) {
    if(!rt) x = y = 0;
    else {
        if(z[rt].w <= k) {
            x = newnode();
            z[x] = z[rt];
            split(z[x].ch[1], k, z[x].ch[1], y);
            update(x);
        } else {
            y = newnode();
            z[y] = z[rt];
            split(z[y].ch[0], k, x, z[y].ch[0]);
            update(y);
        } 
    }
}
inline int findkth(int rt, int k) {
    while(1119) {
        if(k <= z[z[rt].ch[0]].sze)
            rt = z[rt].ch[0];
        else {
            if(z[rt].ch[0]) k -= z[z[rt].ch[0]].sze;
            if(!--k) return rt;
            rt = z[rt].ch[1];
        }
    }
}
int main(){
    n = read();
    go(i, 1, n, 1) {
    	xx = yy = zz = 0;
        int tmp = read(), s = read(); ll a = read();
        rot[i] = rot[tmp];
        if(s == 1) {
            split(rot[i], a, xx, yy);
            rot[i] = merge(merge(xx, newnode(a)), yy);
        } else if(s == 2) {
            split(rot[i], a, xx, zz);
            split(xx, a - 1, xx, yy);
            yy = merge(z[yy].ch[0], z[yy].ch[1]);
            rot[i] = merge(merge(xx, yy), zz);
        } else if(s == 3) {
            split(rot[i], a - 1, xx, yy);
            printf("%lld\n", z[xx].sze + 1);
            rot[i] = merge(xx, yy);
        } else if(s == 4) {
            printf("%lld\n", z[findkth(rot[i], a)].w);
        } else if(s == 5) {
            split(rot[i], a - 1, xx, yy);
            if(xx == 0) {
            	printf("-2147483647\n");
            	continue;
            }
            printf("%lld\n", z[findkth(xx, z[xx].sze)].w);
            rot[i] = merge(xx, yy); 
        } else if(s == 6) {
            split(rot[i], a, xx, yy);
            if(yy == 0) {
            	printf("2147483647\n");
            	continue;
            }
            printf("%lld\n", z[findkth(yy, 1)].w);
            rot[i] = merge(xx, yy);
        }
    }
    return 0;
}

2.13整体二分

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int LOG=30,N=1e5+100;
int sum[N*LOG],lc[N*LOG],rc[N*LOG];
int root,cnt;
typedef long long ll;
#define mid ((l+r)>>1)
const int V=1e5+10;
int tt=0;
void pushup(int node){
    sum[node]=sum[lc[node]]+sum[rc[node]];
}

void tov(int &node,int l,int r,int x,int v){
    if(node==0) node=++cnt;
    if(l==r) {
        sum[node]=v;return ;
    }
    if(x<=mid) tov(lc[node],l,mid,x,v);
    if(x>mid)  tov(rc[node],mid+1,r,x,v);
    pushup(node);
}
void update(int &node,int l,int r,int x,int v){
    if(node==0) node=++cnt;
    if(l==r) {
        sum[node]+=v;return ;
    }
    if(x<=mid) update(lc[node],l,mid,x,v);
    if(x>mid)  update(rc[node],mid+1,r,x,v);
    pushup(node);
}
int query(int node,int l,int r,int ql,int qr){
    if((ql<=l&&r<=qr)||node==0) return sum[node];
    int ans=0;
    if(ql<=mid) ans=ans+query(lc[node],l,mid,ql,qr);
    if(qr>=mid+1) ans=ans+query(rc[node],mid+1,r,ql,qr);
    return ans;
}
struct Node{
    int l,r,k,id,t;
}q[N*3],q1[N*3],q2[N*3];
int a[N*3];
int tot=0,ans[N];
void solve(int ql,int qr,int L,int R){
    // cout<<ql<<" "<<qr<<" "<<L<<" "<<R<<endl;
    if(ql>qr) return ;
    if(L==R){
        for(int i=ql;i<=qr;i++)
            if(q[i].id!=0) {
                ans[q[i].id]=L;}
        return ;
    }
    int len1,len2,Mid=L+R>>1;
    len1=len2=0;
    for(int i=ql;i<=qr;i++){
        if(q[i].id==0){
            if(q[i].k<=Mid){
                update(root,0,V,q[i].l,q[i].t);
                q1[++len1]=q[i];
            }
            else {
                q2[++len2]=q[i];
            }
        }else{
            int tmp=query(root,0,V,q[i].l,q[i].r);
            // cout<<tmp<<endl;
            if(tmp>=q[i].k){
                q1[++len1]=q[i];
            }else{
                q[i].k-=tmp;
                q2[++len2]=q[i];
            }
        }
    }
    for (int i = 1; i <= len1; ++ i) q[ql + i - 1] = q1[i];
	for (int i = 1; i <= len2; ++ i) q[ql + len1 + i - 1] = q2[i];
    for (int i = ql; i <= ql + len1 - 1; ++ i)
		if (q[i].id == 0 && q[i].k <= Mid) {
            update(root,0,V,q[i].l,-q[i].t);
        }
			
    solve(ql, ql + len1 - 1, L, Mid);
	solve(ql + len1, qr, Mid + 1, R);
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int n,m;cin>>n>>m;
    for(int i=1,x;i<=n;i++){
        cin>>x;
        a[i]=x;
        q[++tot]={i,i,x,0,1};
    }

    for(int i=1;i<=m;i++){
        char s;cin>>s;
        if(s=='Q'){
            int l,r,k;
            cin>>l>>r>>k;
            q[++tot]={l,r,k,++tt};
        }else{
            int l,v;
            cin>>l>>v;
            q[++tot]={l,l,a[l],0,-1};
            q[++tot]={l,l,v,0,1};
            a[l]=v;
        }
    }
    solve(1,tot,0,1e9+10);
    for(int i=1;i<=tt;i++){
        cout<<ans[i]<<endl;
    }
}

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int N = 1010, M = 1e6 + 10;
struct Node {
	int x, y, u, v, k, id;
    //(x,y)(u,v)矩阵左上,右下角
} q[M + N], q1[N + M], q2[N + M];
int tot = 0, n, m, tree[N][N], ans[M];

//树状数组
inline void add(int x, int y, int v) { //修改
	for (int i = x; i <= n; i += i & -i) 
		for (int j = y; j <= n; j += j & -j)
			tree[i][j] += v;
	return ;
}

inline int query(int x, int y) { //查询二维前缀和
	int res = 0;
	for (int i = x; i; i -= i & -i) 
		for (int j = y; j; j -= j & -j)
			res += tree[i][j];
	return res;
}

inline void solve(int ql, int qr, int L, int R) {
	if (ql > qr) 
		return ;
	if (L == R) { //规模缩小为一个数
		for (int i = ql; i <= qr; ++ i) //记录答案 
			if (q[i].id != 0) ans[q[i].id] = L;
		return ;
	}
	
	int len1, len2, mid = (L + R) >> 1;
	len1 = len2 = 0;
	for (int i = ql; i <= qr; ++ i) {
		if(q[i].id == 0) {
			if (q[i].k <= mid) {
				add(q[i].x, q[i].y, 1);
				q1[++ len1] = q[i];
			} else {
				q2[++ len2] = q[i];
			}
		} else {
			int tmp = query(q[i].u, q[i].v) - query(q[i].x - 1, q[i].v) - query(q[i].u, q[i].y - 1) + query(q[i].x - 1, q[i].y - 1); //提取子矩阵
			if (tmp >= q[i].k) {
				q1[++ len1] = q[i];
			} else {
				q[i].k -= tmp;
				q2[++ len2] = q[i];
			}
		}
	}
	
	for (int i = 1; i <= len1; ++ i) q[ql + i - 1] = q1[i];
	for (int i = 1; i <= len2; ++ i) q[ql + len1 + i - 1] = q2[i];
	
	for (int i = ql; i <= ql + len1 - 1; ++ i)
		if (q[i].id == 0 && q[i].k <= mid) 
			add(q[i].x, q[i].y, -1);
	
	solve(ql, ql + len1 - 1, L, mid);
	solve(ql + len1, qr, mid + 1, R);
}

inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(!isdigit(ch)) { if(ch == '-') f = -f; ch = getchar(); }
	while(isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); }
	return x * f;
}

signed main() {
	n = read(); m = read();
	for (int x, i = 1; i <= n; ++ i)
		for (int j = 1; j <= n; ++ j) {
			x = read();
			q[++ tot] = (Node) {i, j, 0, 0, x, 0};
		}
	for (int x, y, a, b, k, i = 1; i <= m; ++ i) {
		x = read(); y = read(); 
		a = read(); b = read();
		k = read();
		q[++ tot] = (Node) {x, y, a, b, k, i};
	}
	solve(1, tot, INT_MIN, INT_MAX);
	for (int i = 1; i <= m; ++ i)
		printf("%d\n", ans[i]);
	return 0;
} 

2.14树套树

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
template<typename T>void read(T &x){
    x=0;int f(1);char c(getchar());
    for(;!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(; isdigit(c);c=getchar())x=(x<<3)+(x<<1)+(c-'0');
    x*=f;
}
struct node{
    int a,b,c,id;
};
#define mid ((l+r)>>1)
#define ls node<<1
#define rs node<<1|1
#define endl '\n'
typedef  pair<pair<int,int>,int> piii;
typedef long long ll;
map<piii,int>ma;
node a[N];
bool cmp(node x1,node x2){
    if(x1.a!=x2.a) return x1.a<x2.a;
    if(x1.b!=x2.b) return x1.b<x2.b;
    return x1.c<x2.c;
}
const int V=2e5+10;
int n,k;
namespace treap{// 无旋treap (fhq-treap)
    const int N = 200007, INF = 0x3f3f3f3f;
    const int LOG=30;
    struct fhq_treap{
        int l, r;
        int size;
        int fa;
        int val, fix;
        ll sum;
    }tr[N*LOG];

    int cnt;
    int x, y, z, root[N<<2];

    inline void pushup(int p)
    {
        tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + 1;
        tr[p].sum = tr[tr[p].l].sum + tr[tr[p].r].sum + tr[p].val;
        tr[tr[p].l].fa = tr[tr[p].r].fa = p;
    }

    inline void split(int p, int k, int &x, int &y)//split_by_val
    {
        if(!p){x = y = 0; return ;}
        if(tr[p].val <= k)x = p, split(tr[p].r, k, tr[p].r, y);
        else y = p, split(tr[p].l, k, x, tr[p].l);
        pushup(p);
    }

    inline int merge(int x, int y)
    {
        if(!x || !y)return x + y;
        if(tr[x].fix > tr[y].fix){//小根堆
           tr[x].r = merge(tr[x].r, y);pushup(x);return x;
        }
        else {
            tr[y].l = merge(x, tr[y].l);pushup(y);return y;
        }
    }

    //!得到新节点
    inline int get_node(int val)
    {
        tr[++ cnt].size = 1;
        tr[cnt].fix = rand();
        tr[cnt].sum = tr[cnt].val = val;
        tr[cnt].fa = 0;
        return cnt;
    }

    //!树中插入新节点
    inline void my_insert(int k,int val)
    {
        split(root[k], val, x, y);
        root[k] = merge(merge(x, get_node(val)), y);
    }

    //!按值删除所有权值为k的所有点
    inline void my_delet_all(int k,int val)
    {
        split(root[k], val, x, z);
        split(x, val - 1, x, y);
        root[k] = merge(x, z);
        return ;
    }

    //!按值删除给定权值的一个点
    inline void my_delet_one(int k,int val)
    {
        split(root[k], val, x, z);
        split(x, val - 1, x, y);
        y = merge(tr[y].l, tr[y].r);
        root[k] = merge(merge(x, y), z);
        return ;
    }

    //!查询指定排名的一个数,返回那个数的编号
    inline int get_num_by_rank(int p, int k)
    {
        while(true){
            if(k <= tr[tr[p].l].size)p = tr[p].l;
            else if(k == tr[tr[p].l].size + 1)return p;
            else k -= tr[tr[p].l].size + 1, p = tr[p].r;
        }
    }

    //!按权值分裂时查询一个数的排名///

    //!根据权值查询一个数的排名
    inline int get_rank_by_val(int k,int val)
    {
        split(root[k], val - 1, x, y);
        int res = tr[x].size + 1;
        root[k] = merge(x, y);
        return res;
    }

    //!按排名分裂时查询一个数的排名/
    //!需要维护父节点

    //!根据编号查询这个数的排名
    inline int get_rank_by_num(int k,int p)
    {
        int res = tr[tr[p].l].size + 1;
        while(p != root[k]){//一直回溯
            if(p == tr[tr[p].fa].r)res += tr[tr[tr[p].fa].l].size + 1;
            p = tr[p].fa;
        }
        return res;
    }

    inline int get_val_by_rank(int k,int rank)
    {
        int res = tr[get_num_by_rank(root[k], rank)].val;
        return res;
    }


    //!查找前驱的编号
    //!按值查找比它小的数中的最大的数的编号
    inline int get_prev_of_num(int k,int val)
    {
        split(root[k], val - 1, x, y);
        int res = tr[get_num_by_rank(x, tr[x].size)].val;
        root[k] = merge(x, y);
        return res;
    }

    //!查找后继的编号
    //!按值查找比它大的数中最小数的编号
    inline int get_next_of_num(int k,int val)
    {
        split(root[k], val, x, y);
        int res = tr[get_num_by_rank(y, 1)].val;
        root[k] = merge(x, y);
        return res;
    }

    //!查找节点的祖先节点
    inline int get_anc(int x)
    {
        while(tr[x].fa){
            x = tr[x].fa;
        }
        return x;
    }


    inline void main()
    {
        srand((unsigned)time(NULL));
        memset(tr, 0, sizeof tr);
        cnt = 0;
    }
}

void insert(int node,int l,int r,int x,int v){
    treap::my_insert(node,v);
    if(l==r) return;
    if(x<=mid) insert(ls,l,mid,x,v); 
    else insert(rs,mid+1,r,x,v);
}

int query(int node,int l,int r,int ql,int qr,int val){//<=val
    // cout<<node<<" "<<l<<" "<<r<<endl;
    if(ql<=l&&r<=qr){
        return treap::get_rank_by_val(node,val+1)-1;
        return 0;
    }
    int ans=0;
    if(ql<=mid) ans+=query(ls,l,mid,ql,qr,val);
    if(qr>mid ) ans+=query(rs,mid+1,r,ql,qr,val);
    return ans;
}

int ans1[N];
int ans2[N];

int main(){
    srand(time(0));
    // ios::sync_with_stdio(0);
    // cin.tie(0),cout.tie(0);
    // cin>>n>>k;
    read(n),read(k);
    for(int i=1;i<=n;i++) {
        // cin>>a[i].a>>a[i].b>>a[i].c,a[i].id=i;
        read(a[i].a),read(a[i].b),read(a[i].c);a[i].id=i;
        }
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++){
        int tmp=query(1,0,V,0,a[i].b,a[i].c);
        ma[{{a[i].a,a[i].b},a[i].c}]++;
        ans1[i]=tmp;
        // ans2[tmp]++;
        insert(1,0,V,a[i].b,a[i].c);
    }
    for(int i=1;i<=n;i++){
        ans1[i]+=ma[{{a[i].a,a[i].b},a[i].c}]-1;
        ma[{{a[i].a,a[i].b},a[i].c}]-=1;
        // cout<<a[i].a<<" "<<a[i].b<<" "<<a[i].c<<endl;
        // cout<<ans1[i]<<endl;
        ans2[ans1[i]]++;

    }
    for(int i=0;i<n;i++){
        cout<<ans2[i]<<endl;
    }
}

cdq分治

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 100010
#define maxk 200010
#define ll long long 
using namespace std;
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(isdigit(ch)==0 && ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline void write(int x)
{
    int f=0;char ch[20];
    if(!x){puts("0");return;}
    if(x<0){putchar('-');x=-x;}
    while(x)ch[++f]=x%10+'0',x/=10;
    while(f)putchar(ch[f--]);
    putchar('\n');
}
typedef struct node
{
    int x,y,z,ans,w;	
}stnd;
stnd a[maxn],b[maxn];
int n,cnt[maxk];
int k,n_;
bool cmpx(stnd u,stnd v)
{
    if(u.x==v.x)
    {
        if(u.y==v.y)
            return u.z<v.z;
        return u.y<v.y;
    }
    return u.x<v.x;
}
bool cmpy(stnd u,stnd v)
{
    if(u.y==v.y)
        return u.z<v.z;
    return u.y<v.y;
}
struct treearray
{
    int tre[maxk],kk;
    int lwbt(int x){return x&(-x);}
    int ask(int i){int ans=0; for(;i;i-=lwbt(i))ans+=tre[i];return ans;}
    void add(int i,int k){for(;i<=kk;i+=lwbt(i))tre[i]+=k;}
}t;
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=(l+r)>>1;
    cdq(l,mid);cdq(mid+1,r);
    sort(a+l,a+mid+1,cmpy);
    sort(a+mid+1,a+r+1,cmpy);
    int i=mid+1,j=l;
    for(;i<=r;i++)
    {
        while(a[j].y<=a[i].y && j<=mid)
            t.add(a[j].z,a[j].w),j++;
        a[i].ans+=t.ask(a[i].z);
    }
    for(i=l;i<j;i++)
        t.add(a[i].z,-a[i].w);
}
int main()
{
    n_=read(),k=read();t.kk=k;
    for(int i=1;i<=n_;i++)
        b[i].x=read(),b[i].y=read(),b[i].z=read();
    sort(b+1,b+n_+1,cmpx);
    int c=0;
    for(int i=1;i<=n_;i++)
    {
        c++;
        if(b[i].x!=b[i+1].x || b[i].y!=b[i+1].y || b[i].z!=b[i+1].z )
            a[++n]=b[i],a[n].w=c,c=0;
    } 
    cdq(1,n); 	
    for(int i=1;i<=n;i++)
        cnt[a[i].ans+a[i].w-1]+=a[i].w;
    for(int i=0;i<n_;i++)
        write(cnt[i]);
    return 0;
}

2.15lct有根树

#include <bits/stdc++.h>
using namespace std;

constexpr int N = 3e5 + 7;

#define lc c[0]
#define rc c[1]
struct Node { int c[2], fa; bool rev; } t[N];
int S[N];
bool isroot(int o) { return t[t[o].fa].lc != o && t[t[o].fa].rc != o; }
bool idtfy(int o) { return t[t[o].fa].rc == o; }
void connect(int fa, int o, int d) { t[fa].c[d] = o, t[o].fa = fa; }
void pushup(int o) {  }
void pushdown(int o) {
    if (!t[o].rev) return;
    t[o].rev = 0;
    if (t[o].lc) swap(t[t[o].lc].lc, t[t[o].lc].rc), t[t[o].lc].rev ^= 1;
    if (t[o].rc) swap(t[t[o].rc].lc, t[t[o].rc].rc), t[t[o].rc].rev ^= 1;
}
void rotate(int o) {
    int fa = t[o].fa, pa = t[fa].fa, d1 = idtfy(o), d2 = idtfy(fa), b = t[o].c[d1 ^ 1];
    t[o].fa = pa, !isroot(fa) && (t[pa].c[d2] = o);
    connect(fa, b, d1), connect(o, fa, d1 ^ 1);
    pushup(fa), pushup(o);
}
void splay(int o) {
    int x = o, tp = 1;
    S[tp] = x;
    while (!isroot(x)) S[++tp] = x = t[x].fa;
    while (tp) pushdown(S[tp--]);
    while (!isroot(o)) {
        int fa = t[o].fa;
        if (isroot(fa)) rotate(o);
        else if (idtfy(o) == idtfy(fa)) rotate(fa), rotate(o);
        else rotate(o), rotate(o);
    }
}
void access(int o) {
    for (int x = 0; o; x = o, o = t[o].fa)
        splay(o), t[o].rc = x, pushup(o);
}
int findrt(int x) {
    access(x), splay(x);
    while (pushdown(x), t[x].lc) x = t[x].lc;
    return splay(x), x;
}
void mkrt(int x) {
    access(x), splay(x);
    t[x].rev ^= 1, swap(t[x].lc, t[x].rc);
}
int findfa(int x) {
    access(x), splay(x);
    pushdown(x), x = t[x].lc;
    while (pushdown(x), t[x].rc) x = t[x].rc;
    if (x) splay(x);
    return x;
}
void split(int x, int y) { mkrt(x), access(y), splay(y); }
void link(int x, int y) {
    access(x), splay(x), t[x].fa = y;
}
void cut(int x, int y) {
    access(x), splay(x);
    t[x].lc = t[t[x].lc].fa = 0;
    if (t[y].lc == x && t[x].fa == y) t[y].lc = t[x].fa = 0, pushup(y);
}

using pii = pair<int, int>;

int n, m, q, nod;
int bl[N];
set<pii> ps[N];

int get(int id, int x) {
    set<pii> &s = ps[id];
    pii u(x, 0);
    auto p = s.upper_bound(u);
    if (p->first == x) return p->second;
    int old = p->second, oldv = p->first;
    s.erase(p);
    ++nod;
    bl[nod] = id;
    int fa = findfa(old);
    if (fa) cut(old, fa);
    link(old, nod);
    if (fa) link(nod, fa);
    s.emplace(x, old);
    s.emplace(oldv, nod);
    return old;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n >> m >> q;
    for (int i = 1; i <= n; ++i) ++nod, ps[i].emplace(m + 1, nod), bl[nod] = i;
    for (int i = 1; i <= q; ++i) {
        int opt, a, b;
        cin >> opt;
        if (opt == 1) {
            cin >> a >> b;
            int v1 = get(a, b), v2 = get(a + 1, b);
            int f1 = findfa(v1), f2 = findfa(v2);
            if (f1) cut(v1, f1);
            if (f2) cut(v2, f2);
            if (f2) link(v1, f2);
            if (f1) link(v2, f1);
        } else {
            cin >> a;
            cout << bl[findrt(ps[a].begin()->second)] << '\n';
        }
    }

    return 0;
}

2.16点分治

在这里插入图片描述
找重心去做

//niiick
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int inf=10000000;
const int maxn=100010;
int n,m;
struct node{int v,dis,nxt;}E[maxn<<1];
int tot,head[maxn];
int maxp[maxn],size[maxn],dis[maxn],rem[maxn];
int vis[maxn],test[inf],judge[inf],q[maxn];
int query[1010];
int sum,rt;
int ans;

void add(int u,int v,int dis)
{
    E[++tot].nxt=head[u];
    E[tot].v=v;
    E[tot].dis=dis;
    head[u]=tot;
}

void getrt(int u,int pa)
{
    size[u]=1; maxp[u]=0;
    for(int i=head[u];i;i=E[i].nxt) 
    {
        int v=E[i].v;
        if(v==pa||vis[v]) continue;
        getrt(v,u);
        size[u]+=size[v];
        maxp[u]=max(maxp[u],size[v]);
    }
    maxp[u]=max(maxp[u],sum-size[u]);
    if(maxp[u]<maxp[rt]) rt=u;
}

void getdis(int u,int fa)
{
    rem[++rem[0]]=dis[u];
    for(int i=head[u];i;i=E[i].nxt)
    {
        int v=E[i].v;
        if(v==fa||vis[v])continue;
        dis[v]=dis[u]+E[i].dis;
        getdis(v,u);
    }
}

void calc(int u)
{
    int p=0;
    for(int i=head[u];i;i=E[i].nxt)
    {
        int v=E[i].v;
        if(vis[v])continue;
        rem[0]=0; dis[v]=E[i].dis;
        getdis(v,u);//处理u的每个子树的dis

        for(int j=rem[0];j;--j)//遍历当前子树的dis
        for(int k=1;k<=m;++k)//遍历每个询问
        if(query[k]>=rem[j])
        test[k]|=judge[query[k]-rem[j]];
        //如果query[k]-rem[j]d的路径存在就标记第k个询问

        for(int j=rem[0];j;--j)//保存出现过的dis于judge
        q[++p]=rem[j],judge[rem[j]]=1;
    }
    for(int i=1;i<=p;++i)//处理完这个子树就清空judge
    judge[q[i]]=0;//特别注意一定不要用memeset,会T

}

void solve(int u)
{   
    //judge[i]表示到根距离为i的路径是否存在
    vis[u]=judge[0]=1; calc(u);//处理以u为根的子树
    for(int i=head[u];i;i=E[i].nxt)//对每个子树进行分治
    {
        int v=E[i].v;
        if(vis[v])continue;
        sum=size[v]; maxp[rt=0]=inf;//注意sum是以v为根的子树大小
        getrt(v,0); solve(rt);//在子树中找重心并递归处理
    }
}

int main()
{
    n=read();m=read();
    for(int i=1;i<n;++i)
    {
        int u=read(),v=read(),dis=read();
        add(u,v,dis);add(v,u,dis);
    }
    for(int i=1;i<=m;++i)
    query[i]=read();//先记录每个询问以离线处理

    maxp[rt]=sum=n;//第一次先找整棵树的重心
    getrt(1,0); 
    solve(rt);//对树进行点分治

    for(int i=1;i<=m;++i)
    {
        if(test[i]) printf("AYE\n");
        else printf("NAY\n");
    }
    return 0;
}

3.杂项

3.1对拍

#include<bits/stdc++.h>
using namespace std;

int main(){
	while(true){
		system("data.exe > data.txt");
		system("solution.exe < data.txt > solution.txt");
		system("force.exe < data.txt > force.txt");
		if(system("fc solution.txt force.txt"))break;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值