Codeforces 1083C Max Mex
阿新 • • 發佈:2018-12-23
題意
給出一棵\(n\)個節點,以\(1\)為根的樹。
每個節點都有一個權值\(v_i\),\(v_i \in [0,n-1]\)且沒有兩個節點的\(v_i\)相同。
定義\(V\)為樹上某條路徑上的節點的\(v_i\)組成的集合。
給出\(q\)次操作,每次交換兩個節點的\(v_i\)或者詢問所有可能的\(V\)的\(mex\)的\(max\)。
Solution
首先設\(pos_i\)為權值為\(i\)的節點的編號。
那麼每次詢問的答案就是找一個最大的\(k\)滿足,\(pos_i(i \in [0,k-1])\)在同一條鏈上。
考慮線段樹來維護這個東西。
線段樹上每個節點維護一個數對\((x,y)\)
合併左右兒子資訊的時候,如果其中有一個\((-1,-1)\)則當前節點肯定也是\((-1,-1)\),否則當前這個區間的節點所在的那條鏈的兩端肯定是左右兒子的\((x,y)\)其中的兩個數,暴力一波就行了。
#include<bits/stdc++.h> #define For(i,x,y) for (register int i=(x);i<=(y);i++) #define Dow(i,x,y) for (register int i=(x);i>=(y);i--) #define cross(i,k) for (register int i=first[k];i;i=last[i]) #define Debug(x) cerr<<#x<<"="<<(x)<<endl #define mp make_pair #define fi first #define se second using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pa; inline ll read(){ ll x=0;int ch=getchar(),f=1; while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar(); if (ch=='-'){f=-1;ch=getchar();} while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return x*f; } namespace Fuck{ const int N = 2e5+10; int n,q,a[N],fa[N],pos[N]; int tot,first[N],to[N<<1],last[N<<1]; inline void Add(int x,int y){to[++tot]=y,last[tot]=first[x],first[x]=tot;} int cnt,size[N],son[N],dep[N]; inline void dfs(int u){ size[u]=1,dep[u]=dep[fa[u]]+1; cross(i,u){ dfs(to[i]),size[u]+=size[to[i]]; son[u]=size[to[i]]>size[son[u]]?to[i]:son[u]; } } int t[N],l[N]; inline void dfs(int u,int Top){ l[u]=++cnt,t[u]=Top; if (son[u]) dfs(son[u],Top); cross(i,u) if (to[i]!=son[u]) dfs(to[i],to[i]); } inline int Lca(int x,int y){ for (;t[x]!=t[y];x=fa[t[x]]) if (dep[t[x]]<dep[t[y]]) swap(x,y); return dep[x]<dep[y]?x:y; } inline bool In(int x,int y){return l[x]<=l[y]&&l[y]<=l[x]+size[x]-1;}//y in x? int tmp[4]; inline pa operator + (const pa &a,const pa &b){ tmp[0]=a.fi,tmp[1]=a.se,tmp[2]=b.fi,tmp[3]=b.se; For(i,0,3) if (tmp[i]==-1) return mp(-1,-1); if (tmp[1]==tmp[2]&&tmp[2]==tmp[3]&&tmp[0]==tmp[1]) return mp(tmp[0],tmp[1]); For(i,0,3) For(j,i+1,3){ if (tmp[i]==tmp[j]) continue; int lca=Lca(tmp[i],tmp[j]),flag=1; For(k,0,3) if (k!=i&&k!=j) if (!In(lca,tmp[k])||(In(lca,tmp[k])&&!(In(tmp[k],tmp[i])||In(tmp[k],tmp[j])))){flag=0;break;} if (flag) return mp(tmp[i],tmp[j]); } return mp(-1,-1); } pa v[N<<2]; inline void push_up(int u){v[u]=v[u<<1]+v[u<<1^1];} inline void Build(int u,int l,int r){ if (l==r){v[u]=l==n+1?mp(-1,-1):mp(pos[l],pos[l]);return;}int mid=l+r>>1; Build(u<<1,l,mid),Build(u<<1^1,mid+1,r),push_up(u); } inline void update(int u,int l,int r,int ql){ if (l==r){v[u]=mp(pos[l],pos[l]);return;} int mid=l+r>>1;(ql<=mid)?update(u<<1,l,mid,ql):update(u<<1^1,mid+1,r,ql); push_up(u); } inline int Query(int u,int l,int r,pa x){ if (l==r) return l; int mid=l+r>>1;pa tmp=x+v[u<<1]; if (tmp.fi!=-1) return Query(u<<1^1,mid+1,r,tmp); else return Query(u<<1,l,mid,x); } inline void Main(){ n=read(); For(i,1,n) a[i]=read()+1,pos[a[i]]=i; For(i,2,n) fa[i]=read(),Add(fa[i],i); dfs(1),dfs(1,1),Build(1,1,n+1),q=read(); while (q--){ int opt=read(); if (opt==1){ int x=read(),y=read(); swap(a[x],a[y]),pos[a[x]]=x,pos[a[y]]=y; update(1,1,n+1,a[x]),update(1,1,n+1,a[y]); } else printf("%d\n",Query(1,1,n+1,mp(pos[1],pos[1]))-1); } } } int main(){ Fuck::Main(); }