寫過的部分板子
阿新 • • 發佈:2018-11-10
退役之前把自己敲過的板子都發一下,不會有詳細的解釋,只能保證碼風適合大部分人的閱讀習慣
你將會在這篇文章中看到這些模板:
·快讀
·最短路——dijkstra及spfa
·最小生成樹
·LCA的tarjan演算法
·強連通分量的tarjan演算法以及割點的tarjan演算法
·最小樹形圖,朱劉演算法
·最大流,dinic
·差分約束
·乘法逆元線性篩
·Lucas定理
·FFT
·洲閣篩篩素數個數
·樹狀陣列及線段樹
·treap和splay
·樹鏈剖分
·KMP和manacher
好的,那麼開始吧
inline int read(){ int k=0,f=1; char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c<='9'&&c>='0'){k=k*10+c-'0';c=getchar();} return k*f; }快讀
#include <stdio.h> #include <algorithm> #include <queue> usingdijkstra,luogu p3371namespace std; typedef pair<int,int> pr;//dist,num struct edges { int to,val; }; int n,m,s; int dis[10010]; vector<edges> e[10010]; void dijkstra() { priority_queue<pr,vector<pr>,greater<pr> > q; q.push(pr(0,s)); while(!q.empty()) { pr temp=q.top(); q.pop();int nm=temp.second; if(dis[nm]<temp.first) continue; for(int i=0;i<e[nm].size();i++) { if(dis[e[nm][i].to]>dis[nm]+e[nm][i].val) { dis[e[nm][i].to]=dis[nm]+e[nm][i].val; q.push(pr(dis[e[nm][i].to],e[nm][i].to)); } } } for(int i=1;i<=n;i++)printf("%d ",dis[i]); } int main() { for(int i=0;i<=10005;i++) dis[i]=2147483647; int x,y,z; scanf("%d %d %d",&n,&m,&s); dis[s]=0; for(int i=1;i<=m;i++) { scanf("%d %d %d",&x,&y,&z); e[x].push_back({y,z}); } dijkstra(); return 0; }
#include <stdio.h> #include <algorithm> #include <deque> #include <vector> #include <string.h> #define INF 1000000007 using namespace std; struct node { int to,val; }u; deque<int> deq; int work(int n,int m) { deq.clear(); vector<node> poi[120]; int dis[120]; bool visit[120]; int x,y,v; int now; int k; memset(visit,false,sizeof(visit)); fill(dis,dis+111,INF); for(int i=1;i<=m;i++) { scanf("%d %d %d",&x,&y,&v); u.val=v; u.to=y; poi[x].push_back(u); u.to=x; poi[y].push_back(u); } visit[1]=true; dis[1]=0; deq.push_back(1); while(!deq.empty()) { now=deq.front(); deq.pop_front(); visit[now]=false; for(int i=0;i<poi[now].size();i++) { if(dis[poi[now][i].to]>dis[now]+poi[now][i].val) { dis[poi[now][i].to]=dis[now]+poi[now][i].val; if(!visit[poi[now][i].to]) { visit[poi[now][i].to]=true; if(deq.empty()) deq.push_front(poi[now][i].to); else { k=deq.front(); if(dis[poi[now][i].to]<dis[k]) deq.push_front(poi[now][i].to); else deq.push_back(poi[now][i].to); } } } } } return dis[n]; } int main() { int n,m; while(1) { scanf("%d %d",&n,&m); if(n==0&&m==0) return 0; else { printf("%d\n",work(n,m)); } } return 0; }spfa,hdu2544
#include <stdio.h> #include <algorithm> using namespace std; struct Edges { int a,b; long long len; }e[200100]; int n,m; int f[50020]; inline bool cmp(struct Edges a,struct Edges b) {return a.len<b.len;} inline int findf(int a) { if(f[a]==a) return a; else { f[a]=findf(f[a]); return f[a]; } } inline void merge(int a,int b) { int x=findf(a),y=findf(b); f[x]=y; } int main() { int ej=0; long long ans=0; scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) { f[i]=i; } int x,y; long long l; for(int i=1;i<=m;i++) { scanf("%d %d %lld",&e[i].a,&e[i].b,&e[i].len); } sort(e+1,e+m+1,cmp); for(int i=1;i<=m;i++) { if(findf(e[i].a)!=findf(e[i].b)) { ej++; ans+=e[i].len; merge(e[i].a,e[i].b); } } if(ej<n-1) { printf("orz"); return 0; } printf("%lld",ans); return 0; }最小生成樹kruskal,luogu p3366
#include <stdio.h> #include <algorithm> #include <vector> #include <cstring> using namespace std; struct questions { int next,sum,ans,num; }q[1000005]; int qans[500100]; struct edges { int to,next; }e[1000005]; bool visit[500100],vis[500100]; int treef[500100],uff[500100],anc[500100]; int heade[500100],headq[500100]; int n,m,s; int sume,sumq; inline int read() { int f=1,k=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){k=k*10+c-'0';c=getchar();} return k*f; } int buf[10]; inline int write(int i) { int p=0; if(i==0) p++; else while(i) { buf[p++]=i%10; i/=10; } for(int j=p-1;j>=0;j--) putchar('0'+buf[j]); } inline int findf(int a) { if(uff[a]==a) return a; else { uff[a]=findf(uff[a]); return uff[a]; } } inline void merge(int a,int b) { int x=findf(a),y=findf(b); uff[x]=y; } inline void LCA(int now) { visit[now]=true; for(int i=heade[now];i;i=e[i].next) { if(!visit[e[i].to]) { LCA(e[i].to); merge(now,e[i].to); //printf("%d %d\n",now,e[i].to); } anc[findf(now)]=now; } vis[now]=true; //printf("now=%d findf(now)=%d\n",now,findf(now)); //for(int i=1;i<=n;i++) printf("%d ",uff[i]); //for(int i=1;i<=n;i++) printf("%d ",anc[i]); //printf("\n"); for(int i=headq[now];i;i=q[i].next) { int x=q[i].sum; //printf(" %d %d\n",now,x); if(vis[x]) { q[i].ans=anc[findf(x)]; //printf("now=%d findfnow=%d ans=%d num=%d\n",now,findf(now),q[i].ans,q[i].num); qans[q[i].num]=q[i].ans; } } } int main() { int x,y; n=read();m=read();s=read(); for(int i=1;i<=n-1;i++) { x=read();y=read(); e[++sume].to=y; e[sume].next=heade[x]; heade[x]=sume; e[++sume].to=x; e[sume].next=heade[y]; heade[y]=sume; } for(int i=1;i<=m;i++) { x=read();y=read(); q[++sumq].next=headq[x]; q[sumq].sum=y; q[sumq].num=i; headq[x]=sumq; q[++sumq].next=headq[y]; q[sumq].sum=x; q[sumq].num=i; headq[y]=sumq; } for(int i=1;i<=n;i++) { uff[i]=i; anc[i]=0; } LCA(s); for(int i=1;i<=m;i++) { write(qans[i]); printf("\n"); } return 0; }LCA tarjan,luogu p3379
#include <stdio.h> #include <algorithm> #include <set> #include <vector> #include <stack> using namespace std; vector<int> edges[5050]; set<int> se[5050]; stack<int> st; int dfn[5050],lowlink[5050]; int dfsno,seno,n,m; bool instk[5050]; void DFS(int now) { dfn[now]=lowlink[now]=++dfsno; st.push(now); instk[now]=true; for(int i=0;i<edges[now].size();i++) { int t=edges[now][i]; if(!dfn[t]) { DFS(t); lowlink[now]=min(lowlink[now],lowlink[t]); } else if(instk[t]) lowlink[now]=min(lowlink[now],dfn[t]); } if(lowlink[now]==dfn[now]) { seno++; while(1) { int p=st.top(); st.pop(); instk[p]=false; se[seno].insert(p); if(p==now) break; } } } int main() { int x,y,op; scanf("%d %d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d %d %d",&x,&y,&op); if(op==1) edges[x].push_back(y); else if(op==2) { edges[x].push_back(y); edges[y].push_back(x); } } for(int i=1;i<=n;i++) { if(!dfn[i]) DFS(i); } int ans=1; for(int i=2;i<=seno;i++) { if(se[i].size()>se[ans].size()||(se[i].size()==se[ans].size()&&*(se[i].begin())>*(se[ans].begin()))) ans=i; } printf("%d\n",se[ans].size()); for(set<int>::iterator it=se[ans].begin();it!=se[ans].end();it++) { printf("%d ",*it); } return 0; }強聯通分量tarjan,luogu p1726
#include <stdio.h> #include <algorithm> #include <cstring> using namespace std; struct izayoi { int to,next; }e[200200]; int head[100100],num; int dfn[100100],lowlink[100100]; int n,m,cnt; bool cut[100100]; bool flag[100100]; void add(int from,int to) { e[++num].to=to; e[num].next=head[from]; head[from]=num; } void DFS(int now) { dfn[now]=lowlink[now]=++cnt; int child=0; for(int i=head[now];i;i=e[i].next) { if(!dfn[e[i].to]) { DFS(e[i].to); lowlink[now]=min(lowlink[now],lowlink[e[i].to]); if(lowlink[e[i].to]>=dfn[now]&&(!flag[now])) cut[now]=true; if(flag[now]) child++; } lowlink[now]=min(lowlink[now],dfn[e[i].to]); } if(flag[now]&&child>=2) cut[now]=true; } int main() { //freopen("p3388.in","r",stdin); scanf("%d %d",&n,&m); for(int i=1;i<=m;i++) { int x,y; scanf("%d %d",&x,&y); add(x,y);add(y,x); } for(int i=1;i<=n;i++) { if(!dfn[i]) flag[i]=true,DFS(i); } int ans=0; for(int i=1;i<=n;i++) { if(cut[i]) ans++; } printf("%d\n",ans); for(int i=1;i<=n;i++) { if(cut[i])printf("%d ",i); } return 0; }割點tarjan,luogu p3388
#include <stdio.h> #include <algorithm> #include <cstring> using namespace std; const int INF=1000000009; inline int read() { int k=0,f=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c<='9'&&c>='0'){k=k*10+c-'0';c=getchar();} return k*f; } int n,m,root; struct izyoi { int x,y; int val; }e[10010]; int pre[110],id[110]; int visit[110]; int in[110]; int Zhu_Liu(int root) { int ans=0,cnt=0; while(1) { cnt=0; memset(id,0,sizeof(id)); memset(visit,0,sizeof(visit)); fill(in+1,in+n+1,INF); for(int i=1;i<=m;i++) { int x=e[i].x,y=e[i].y; if(in[y]>e[i].val&&x!=y) pre[y]=x,in[y]=e[i].val; } in[root]=0; for(int i=1;i<=n;i++) if(in[i]==INF) return -1; for(int i=1;i<=n;i++) { ans+=in[i]; int v=i; while(visit[v]!=i&&!id[v]&&v!=root) { visit[v]=i; v=pre[v]; } if(v!=root&&!id[v]) { id[v]=++cnt; for(int u=pre[v];u!=v;u=pre[u]) id[u]=cnt; } } if(!cnt) break; for(int i=1;i<=n;i++) if(!id[i]) id[i]=++cnt; for(int i=1;i<=m;i++) { int x=e[i].x,y=e[i].y; e[i].x=id[x];e[i].y=id[y]; if(id[x]!=id[y]) e[i].val-=in[y]; } n=cnt; root=id[root]; } return ans; } int main() { n=read();m=read();root=read(); int x,y,z; for(int i=1;i<=m;i++) { x=read();y=read();z=read(); if(x!=y) { e[i].x=x; e[i].y=y; e[i].val=z; } else { i--;m--; } } printf("%d",Zhu_Liu(root)); return 0; }最小樹形圖 朱劉演算法,luogu p4716
#include <stdio.h> #include <algorithm> #include <vector> #include <queue> #include <string.h> #include <iostream> #define INF 1000000007 using namespace std; typedef long long llw; inline int read() { llw k=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){k=k*10+c-'0';c=getchar();} return k*f; } long long n,m,s,t; struct edges { llw from,to,cap,flow; }; vector<edges> eds; vector<llw> gra[1001000]; bool visit[1001000]; llw dis[1001000]; llw cur[1001000]; bool BFS() { memset(visit,false,sizeof(visit)); queue<llw> que; llw x; que.push(s); dis[s]=0; visit[s]=true; while(!que.empty()) { x=que.front(); que.pop(); for(llw i=0;i<gra[x].size();i++) { edges& e=eds[gra[x][i]]; if(!visit[e.to]&&e.cap>e.flow) { visit[e.to]=true; dis[e.to]=dis[x]+1; que.push(e.to); } } } return visit[t]; } llw DFS(llw now,llw a) { //printf("%d\n",now); if(now==t||a==0) return a; long long flow=0,f; //printf("%lld\n",now); for(llw &i=cur[now];i<gra[now].size();i++) { edges& e=eds[gra[now][i]]; if(dis[now]+1==dis[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0) { e.flow+=f; eds[gra[now][i]^1].flow-=f; flow+=f; a-=f; if(a==0) break; } } return flow; } int main() { //freopen("p3376.in","r",stdin); int x,y,z; n=read();m=read();s=read();t=read(); //printf("%lld %lld %lld %lld\n",n,m,s,t); for(int i=0;i<m;i++) { //printf("%d\n",i); x=read();y=read();z=read(); eds.push_back((edges){x,y,z,0}); eds.push_back((edges){y,x,0,0}); int k=eds.size(); gra[x].push_back(k-2); gra[y].push_back(k-1); //printf("%d\n",k); } int flow=0; while(BFS()) { memset(cur,0,sizeof(cur)); flow+=DFS(s,INF); } cout<<flow; return 0; }網路最大流dinic,loj101
#include <stdio.h> #include <algorithm> using namespace std; const int INF=100000007; struct izyoi { int to,val,next; }edges[250000]; int num; int head[50000]; inline void add(int x,int y,int val) { edges[++num].to=y; edges[num].val=val; edges[num].next=head[x]; head[x]=num; } int dis[50000]; bool visit[50000]; int n,m; bool spfa(int now) { visit[now]=true; for(int i=head[now];i;i=edges[i].next) { if(dis[edges[i].to]<dis[now]+edges[i].val) { dis[edges[i].to]=dis[now]+edges[i].val; if(visit[edges[i].to]) return false; if(!spfa(edges[i].to)) return false; } } visit[now]=false; return true; } int main() { scanf("%d %d",&n,&m); int opt,a,b,c; for(int i=1;i<=m;i++) { scanf("%d",&opt); if(opt==3) { scanf("%d %d",&a,&b); add(a,b,0); add(b,a,0); } else if(opt==1) { scanf("%d %d %d",&a,&b,&c); add(b,a,c); } else { scanf("%d %d %d",&a,&b,&c); add(a,b,-c); } } fill(dis+1,dis+22000,-INF); for(int i=1;i<=n;i++) add(0,i,0); if(!spfa(0)) printf("No"); else printf("Yes"); return 0; }差分約束,luogu p1993
#include <stdio.h> #include <algorithm> using namespace std; long long inv[7000000]; long long p,n; int main() { scanf("%lld %lld",&n,&p); inv[1]=1; for(int i=2;i<=n;i++) { inv[i]=(p-p/i)*inv[p%i]%p; } for(int i=1;i<=n;i++) { printf("%lld\n",inv[i]); } return 0; }乘法逆元線性篩,loj110
#include <stdio.h> #include <algorithm> using namespace std; typedef long long llw; llw fac[100100]; llw n,m,p; llw fp(llw a,llw x,llw mod) { llw ans=1; while(x>0) { if(x&1) ans*=a; a*=a; x>>=1; ans%=mod;a%=mod; } return ans; } llw C(llw n,llw m,llw p) { if(m>n) return 0; return (fac[n]*fp((fac[m]*fac[n-m])%p,p-2,p))%p; } llw Lucas(llw n,llw m,llw p) { if(n<p&&m<p) return C(n,m,p); return (Lucas(n/p,m/p,p)*C(n%p,m%p,p))%p; } int main() { freopen("p3807.in","r",stdin); int T; scanf("%d",&T); while(T--) { scanf("%lld %lld %lld",&n,&m,&p); fac[0]=1; for(int i=1;i<=p;i++) fac[i]=fac[i-1]*i%p; printf("%lld\n",Lucas(n+m,m,p)); } return 0; }Lucas定理,luogu p3807
#include <stdio.h> #include <algorithm> #include <complex> #include <cmath> #include <cstdlib> using namespace std; inline int read() { int k=0,f=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c<='9'&&c>='0'){k=(k<<1)+(k<<3)+c-'0';c=getchar();} return k*f; } const double PI=acos(-1); complex<double> omega[3000000],omegaInverse[3000000]; complex<double> c1[3000000],c2[3000000]; int n,m; int a1[1000010],a2[1000010]; void transform(complex<double> *a,int n,complex<double> *omega) { int k=0; while((1<<k)<n) k++; for(int i=0;i<n;i++) { int t=0; for(int j=0;j<k;j++) if(i&(1<<j)) t|=(1<<(k-j-1)); if(i<t) swap(a[i],a[t]); } for(int l=2;l<=n;l<<=1) { int m=l/2; for(complex<double> *p=a;p!=a+n;p+=l) { for(int i=0;i<m;i++) { complex<double> t=omega[n/l*i]*p[m+i]; p[i+m]=p[i]-t; p[i]+=t; } } } } int main() { n=read();m=read(); int t; for(int i=0;i<=n;i++) a1[i]=read(),c1[i].real(a1[i]); for(int i=0;i<=m;i++) a2[i]=read(),c2[i].real(a2[i]); if(n==0) { for(int i=0;i<=m;i++) printf("%d ",a1[0]*a2[i]); return 0; } else if(m==0) { for(int i=0;i<=n;i++) printf("%d ",a2[0]*a1[i]); return 0; } for(t=1;t<m+n;t<<=1); for(int i=0;i<t;i++) { omega[i]=complex<double>(cos(2*PI/t*i),sin(2*PI/t*i)); omegaInverse[i]=conj(omega[i]); } transform(c1,t,omega);transform(c2,t,omega); for(int i=0;i<t;i++) c1[i]*=c2[i]; transform(c1,t,omegaInverse); for(int i=0;i<t;i++) c1[i]/=t; for(int i=0;i<=n+m;i++) printf("%d ",(int)floor(c1[i].real()+0.5)); return 0; }FFT,luogu p3803
#include <stdio.h> #include <algorithm> #include <cmath> #include <cstring> using namespace std; typedef long long llw; llw p[500000],pre[500000],tot; bool visit[500000]; llw num,last[2000000]; llw g[2000000],val[2000000]; void pr(llw m) { memset(p,0,sizeof(p)); memset(pre,0,sizeof(pre)); memset(visit,false,sizeof(visit)); for(llw i=2;i<=m;i++) { pre[i]=pre[i-1]; if(!visit[i]) { p[++tot]=i;pre[i]++; } for(llw j=1;j<=tot&&(llw)i*p[j]<=m;j++) { visit[i*p[j]]=true; } } } llw cal(llw m) { if(m<=0)return 0; memset(last,0,sizeof(last)); num=0; llw hlf=(llw)sqrt(m); llw fles=upper_bound(p+1,p+tot+1,hlf)-p-1; for(llw i=m;i>=1;i=m/(m/i+1)) val[++num]=m/i; for(llw i=1;i<=num;i++) g[i]=val[i]; for(llw i=1;i<=fles;i++) { for(llw j=num;j>=1;j--) { llw k=val[j]/p[i];if(k<p[i]) break; k=k<hlf?k:num-m/k+1; g[j]-=g[k]-(i-last[k]-1); last[j]=i; } } return pre[hlf]+g[num]-1; } int main() { llw n; scanf("%lld",&n); pr((llw)sqrt(n)+1); printf("%lld\n",cal(n)); return 0; }洲閣篩篩素數個數 luogu p6235
#include <stdio.h> #include <stdlib.h> #include <string.h> #define lowbit(i) ((i)&(-i)) int f[102000],ans[52000],t=0; int n,m; void update(int x,int v) { for(int i=x;i<=n;i+=lowbit(i)) { f[i]+=v; } } int getnum(int x) { int sum=0; for(int i=x;i>0;i-=lowbit(i)) { sum+=f[i]; } return sum; } int main() { memset(f,0,sizeof(f)); int i,x,a,b,c; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&x); update(i,x); } //for(i=1;i<=n;i++)printf(" %d ",f[i]); scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%d %d %d",&a,&b,&c); if(a==1) { update(b,c); } else ans[++t]=getnum(c)-getnum(b-1); } for(i=1;i<=t;i++)printf("%d\n",ans[i]); return 0; }樹狀陣列_1,codevs1080
#include <stdio.h> #define lowbit(i) ((i)&(-i)) int p[100005],n,m,ans[100010],t=0; void update(int x,int v) { for(int i=x;i>0;i-=lowbit(i)) { p[i]+=v; } } int getsum(int x) { int s=0; for(int i=x;i<=n;i+=lowbit(i)) { s+=p[i]; } return s; } int main() { int i,x,a,b,c,d; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&x); update(i,x); update(i-1,-x); } scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%d",&a); if(a==1) { scanf("%d %d %d",&b,&c,&d); update(c,d); update(b-1,-d); } else { scanf("%d",&b); ans[++t]=getsum(b); } } for(i=1;i<=t;i++)printf("%d\n",ans[i]); return 0; }樹狀陣列_2,codevs1081
#include <stdio.h> #include <algorithm> using namespace std; long long t[666666]; long long lazy[666666]; long long s[666666]; void build(int now,int l,int r) { lazy[now]=0; if(l==r) s[now]=t[l]; else { int mid=(l+r)/2; int lchild=now<<1; int rchild=lchild|1; build(lchild,l,mid); build(rchild,mid+1,r); s[now]=s[lchild]+s[rchild]; } } void PushDown(int now,int l,int r,int mid,int lchild,int rchild) { //int lchild=now<<1; //int rchild=lchild|1; //int mid=(l+r)/2; lazy[lchild]+=lazy[now]; lazy[rchild]+=lazy[now]; s[lchild]+=(mid-l+1)*lazy[now]; s[rchild]+=(r-mid)*lazy[now]; lazy[now]=0; } void Upd(int now,int l,int r,int lrequest,int rrequest,int k) { if(l>=lrequest&&r<=rrequest) { s[now]+=k*(r-l+1); lazy[now]+=k; return; } else { int mid=(l+r)/2; int lchild=now<<1; int rchild=lchild|1; if(lazy[now]!=0) PushDown(now,l,r,mid,lchild,rchild); if(lrequest<=mid) Upd(lchild,l,mid,lrequest,rrequest,k); if(rrequest>mid) Upd(rchild,mid+1,r,lrequest,rrequest,k); s[now]=s[lchild]+s[rchild]; } } long long Query(int now,int l,int r,int lrequest,int rrequest) { if(l>=lrequest&&r<=rrequest) return s[now]; else { int mid=(l+r)/2; int lchild=now<<1; int rchild=lchild|1; long long ans=0; if(lazy[now]!=0) PushDown(now,l,r,mid,lchild,rchild); if(lrequest<=mid) ans+=Query(lchild,l,mid,lrequest,rrequest); if(rrequest>mid) ans+=Query(rchild,mid+1,r,lrequest,rrequest); return ans; } } int main() { int n,m,x,l,r; long long k; scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) { scanf("%lld",&t[i]); } build(1,1,n); for(int i=1;i<=m;i++) { scanf("%d",&x); if(x==1) { scanf("%d %d %lld",&l,&r,&k); //printf("\n"); //for(int i=1;i<=2*n-1;i++) printf("%lld ",s[i]); //printf("\n"); Upd(1,1,n,l,r,k); } else { scanf("%d %d",&l,&r); printf("%lld\n",Query(1,1,n,l,r)); } } return 0; }線段樹,luogu p3372
#include <stdio.h> #include <algorithm> using namespace std; int ch[100100][2],v[100100],rd[100100],cnt[100100],sze[100100],id; int root; #define lc ch[now][0] #define rc ch[now][1] void update(int now) { sze[now]=sze[lc]+sze[rc]+cnt[now]; } void rotate(int &now,int d) { int v=ch[now][d^1]; ch[now][d^1]=ch[v][d]; ch[v][d]=now; update(now); update(now=v); } void insert(int &now,int val) { if(!now) { now=++id; lc=rc=0; v[now]=val; rd[now]=rand(); sze[now]=cnt[now]=1; return; } if(val==v[now]) { cnt[now]++;sze[now]++; return; } int d=(v[now]<val); insert(ch[now][d],val); sze[now]++; if(rd[now]>rd[ch[now][d]])rotate(now,d^1); } bool remove(int &now,int val) { if(!now) return false; if(v[now]==val) { if(cnt[now]>1) { sze[now]--;cnt[now]--; return true; } if(!lc||!rc) { now=lc?lc:rc; return true; } if(rd[lc]>rd[rc]) rotate(now,0); else rotate(now,1); return remove(now,val); } int d=(v[now]<val); if(!remove(ch[now][d],val)) return false; sze[now]--; return true; } int find_rnk(int val) { int now=root,rnk=1; while(now) { if(val<v[now]) now=lc; else if(val>v[now]) { rnk+=sze[lc]+cnt[now]; now=rc; } else return rnk+sze[lc]; } return 0; } int find_val(int rnk) { int now=root; while(now) { if(rnk<=sze[lc]) now=lc; else if(rnk>sze[lc]+cnt[now]) { rnk-=(sze[lc]+cnt[now]); now=rc; } else return v[now]; } return 0; } int find_pre(int val) { int now=root,pre; while(now) { if(v[now]<val) { pre=v[now]; now=rc; } else now=lc; } return pre; } int find_nxt(int val) { int now=root,nxt; while(now) { if(v[now]>val) {