# 个人acm模板整理

2 篇文章 0 订阅

## 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;
inline char gc(){
static char now[1<<16],*S,*T;
return *S++;
}
#endif
#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;
}
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(){
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)的原根）

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;
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(){
for(int i=1;i<=n;i++){
spl.Insert(a[i]);
}
int lastans=0;
for(int i=1;i<=m;i++){
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 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];

edge[cnt].to=y;
edge[cnt].val=v;
}

int cnt1=1;
edge1[cnt1].to=y;
edge1[cnt1].val=v;
}

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++;
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){
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){
int son=edge1[i].to;
cle(son);
}
ta[x]=tb[x]=tc[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(){

t=(int)(log(n)/log(2))+1;
cnt=1;
memset(fa,0,sizeof fa);
dfscnt=1,top=0;
dep[1]=1;
dfs(1);
// cout<<endl;
while(q--){
top=0;
vector<int>v;
int a,b,c;
v.push_back(1);
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]){
if(lc!=stak[top-1])
stak[top]=lc;
else top--;
}
break;
}
else {
top--;
}
stak[++top]=now;
}
while(--top)
cal(1);
}

}

int main(){
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(线段树)

/*平衡树实际上画出来是一颗乱糟糟的小根堆，但是满足小根堆的性质，

/*最后中序遍历输出值即可*/
#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();
}
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){
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);
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);
}

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);
}
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];
{
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++)
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
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(){
go(i, 1, n, 1) {
xx = yy = zz = 0;
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) {
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)

solve(ql, ql + len1 - 1, L, mid);
solve(ql + len1, qr, mid + 1, R);
}

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() {
for (int x, i = 1; i <= n; ++ i)
for (int j = 1; j <= n; ++ j) {
q[++ tot] = (Node) {i, j, 0, 0, x, 0};
}
for (int x, y, a, b, k, i = 1; i <= m; ++ i) {
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;
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;
for(int i=1;i<=n;i++) {
// cin>>a[i].a>>a[i].b>>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;
{
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;}
}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)
}
for(i=l;i<j;i++)
}
int main()
{
for(int i=1;i<=n_;i++)
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);
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);
} 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 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 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;

{
E[tot].v=v;
E[tot].dis=dis;
}

void getrt(int u,int pa)
{
size[u]=1; maxp[u]=0;
{
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];
{
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;
{
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为根的子树
{
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()
{
for(int i=1;i<n;++i)
{
}
for(int i=1;i<=m;++i)

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

• 0
点赞
• 1
收藏
觉得还不错? 一键收藏
• 0
评论
08-05 510
09-13 388
09-12 294
09-11 1185
09-11 320
09-12 484
09-12 586
09-11 435
09-12 969
09-13 1064

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