Max Mex
无法直接处理
可以二分答案!
[0,mid]是否在同一个链上?
可以不修改地做了
修改?
能不能信息合并?可以!
记录包含[l,r]的最短链的两端
可以[0,k][k+1,mid]合并:枚举四个端点中的两个,使得另外两个一定在这两个的路径上
(判断z点在x,y路径上:(lca(x,z)==z||lca(y,z)=z)&&(lca(lca(x,y),z)=lca(x,y))画图即可理解
能合并,所以线段树可以维护。
线段树维护
线段树上二分。
LCA用ST表存
#include<bits/stdc++.h> #define reg register int #define il inline #define fi first #define se second #define mk(a,b) make_pair(a,b) #define numb (ch^'0') using namespace std; typedef long long ll; template<class T>il void rd(T &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');} template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');} template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');} namespace Miracle{ const int N=2e5+5; int n,q; struct node{ int nxt,to; }e[2*N]; int hd[N],cnt; void add(int x,int y){ e[++cnt].nxt=hd[x]; e[cnt].to=y; hd[x]=cnt; } int dep[N]; int a[2*N],tot; int dfn[N]; int f[2*N][20]; int lg[2*N]; int id[N],fid[N]; void dfs(int x,int d){ dep[x]=d; a[++tot]=x; dfn[x]=tot; for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; dfs(y,d+1); a[++tot]=x; } } int big(int x,int y){ return dep[x]<dep[y]?x:y; } int lca(int x,int y){ if(dfn[x]>dfn[y]) swap(x,y); int len=lg[dfn[y]-dfn[x]+1]; return big(f[dfn[x]][len],f[dfn[y]-(1<<len)+1][len]); } int on(int p1,int p2,int p3){ int y=lca(p1,p2); // cout<<" p1 "<<p1<<" p2 "<<p2<<" p3 "<<p3<<" y "<<y<<endl; return ((lca(p1,p3)==p3||lca(p2,p3)==p3)&&(lca(y,p3)==y)); } struct tr{ int p[2]; int can; void init(){ can=p[0]=p[1]=0; } void op(){ cout<<" can "<<can<<" p[0] "<<p[0]<<" p[1] "<<p[1]<<endl; } }t[4*N]; #define ls (x<<1) #define rs (x<<1|1) #define mid ((l+r)>>1) void pushup(int x){ t[x].init(); if(t[x<<1].can&&t[x<<1|1].can){ t[x].can|=on(t[ls].p[0],t[ls].p[1],t[rs].p[0])&&on(t[ls].p[0],t[ls].p[1],t[rs].p[1]); if(t[x].can==1) {t[x].p[0]=t[ls].p[0],t[x].p[1]=t[ls].p[1];return;} t[x].can|=on(t[rs].p[0],t[rs].p[1],t[ls].p[0])&&on(t[rs].p[0],t[rs].p[1],t[ls].p[1]); if(t[x].can==1) {t[x].p[0]=t[rs].p[0],t[x].p[1]=t[rs].p[1];return;} if(!t[x].can){ for(reg i=0;i<=1;++i){ for(reg j=0;j<=1;++j){ t[x].can|=on(t[ls].p[i],t[rs].p[j],t[ls].p[i^1])&&on(t[ls].p[i],t[rs].p[j],t[rs].p[j^1]); if(t[x].can==1) {t[x].p[0]=t[ls].p[i],t[x].p[1]=t[rs].p[j];return;} } } } } } tr merge(tr A,tr B){ tr C;C.can=C.p[0]=C.p[1]=0; // cout<<" A ";A.op(); // cout<<" B ";B.op(); if(A.can&&B.can){ C.can|=on(A.p[0],A.p[1],B.p[0])&&on(A.p[0],A.p[1],B.p[1]); if(C.can==1) {C.p[0]=A.p[0],C.p[1]=A.p[1];return C;} C.can|=on(B.p[0],B.p[1],A.p[0])&&on(B.p[0],B.p[1],A.p[1]); if(C.can==1) {C.p[0]=B.p[0],C.p[1]=B.p[1];return C;} if(!C.can){ for(reg i=0;i<=1;++i){ for(reg j=0;j<=1;++j){ C.can|=on(A.p[i],B.p[j],A.p[i^1])&&on(A.p[i],B.p[j],B.p[j^1]); if(C.can==1) {C.p[0]=A.p[i],C.p[1]=B.p[j];return C;} } } } } return C; } void build(int x,int l,int r){ if(l==r){ t[x].p[0]=t[x].p[1]=fid[l]; t[x].can=1;return; } t[x].can=0; build(x<<1,l,mid); build(x<<1|1,mid+1,r); pushup(x); } void upda(int x,int l,int r,int p,int c){//pos to c if(l==r){ t[x].p[0]=c;t[x].p[1]=c; t[x].can=1;return; } if(p<=mid) upda(ls,l,mid,p,c); else upda(rs,mid+1,r,p,c); pushup(x); } tr tmp; int query(int x,int l,int r){ // cout<<" query "<<x<<" "<<l<<" "<<r<<" : ";t[x].op(); tr C; if(l==r){ if(tmp.can==-1){ C=t[x]; }else{ C=merge(tmp,t[x]); } return C.can==1?l:l-1; } // cout<<" ls ";t[ls].op(); if(tmp.can==-1){ C=t[ls]; }else{ C=merge(tmp,t[ls]); } // C.op(); if(C.can){ tmp=C; return query(rs,mid+1,r); }else{ return query(ls,l,mid); } } int main(){ rd(n); for(reg i=1;i<=n;++i){ rd(id[i]);fid[id[i]]=i; } int y; for(reg i=2;i<=n;++i){ rd(y);add(y,i); } dfs(1,1); for(reg i=1;i<=2*n-1;++i){ lg[i]=(i>>(lg[i-1]+1))?lg[i-1]+1:lg[i-1]; f[i][0]=a[i]; } // cout<<" tot "<<tot<<endl; // prt(a,1,tot); // prt(lg,1,2*n-1); for(reg j=1;j<=19;++j){ for(reg i=1;i+(1<<j)-1<=tot;++i){ f[i][j]=big(f[i][j-1],f[i+(1<<(j-1))][j-1]); } } build(1,0,n-1); rd(q); int op,x; while(q--){ rd(op); if(op==1){ rd(x);rd(y); upda(1,0,n-1,id[x],y); upda(1,0,n-1,id[y],x); swap(id[x],id[y]); }else{ tmp.init(); tmp.can=-1; printf("%d\n",query(1,0,n-1)+1); } } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/4/11 16:56:19 */
正难则反考虑二分检验。
和[IOI2018] seats 排座位有点像,维护前缀信息的连通性
修改?能否两两区间合并?树上链的信息合并的套路。