简要题意:
给一棵有根树,强制在线,支持动态加叶子,询问一个子树的自同构变换个数。
题解:
一句话题解:SBT+封装双哈希+原根倒base+LCT维护三个标记
顺便说一下,博主并不清楚有没有什么离线处理方式
以前确实没有见过LCT拿来维护轻重链剖分这种东西的。。。(LCT维护的东西一般称为虚实链剖分)
首先考虑一个显然的暴力,维护树哈希,然后每次加叶子暴力跳所有父亲并修改哈希值,就可以直接维护答案了。
我们发现并不能暴力维护,复杂度显然假完了。
考虑一下答案的表示式,设 c n t [ p ] cnt[p] cnt[p]表示子树中哈希值为 p p p的有多少个, t r [ p ] tr[p] tr[p]表示以 p p p为根的子树内部的自同构变换个数,则 u u u的计算式就是 ∏ c n t [ p ] ! ∏ v ∈ s o n ( u ) t r [ v ] \prod cnt[p]!\prod_{v\in son(u)}tr[v] ∏cnt[p]!∏v∈son(u)tr[v]
感觉还是没法做啊。。。。
定义重儿子为 s i z [ v ] ∗ 2 ≥ s i z [ u ] siz[v]*2\geq siz[u] siz[v]∗2≥siz[u]的孩子 v v v。
显然每个点要么没有重儿子,要么只有一个重儿子,并且重儿子一定不和任何一个其他子树同构。
用LCT维护一条重链,显然如果我们在链中间某个点改了答案,显然只会一路改上去,并且由于出现次数都是1次,改的就只有 t r [ u ] tr[u] tr[u]部分,相当于整条链点的答案乘上一个值。
注意到我们从任何一片叶子开始跳父亲,最多只会跳 O ( log n ) O(\log n) O(logn)条轻边。
在这些地方暴力修改即可。
那么问题就只剩下如何维护树哈希值。
由于我们能够保证重儿子只出现了一次,那么直接考虑普通的排序+模质数的进制哈希。
由于要维护排序,所以用一个支持单点插入,单点删除,计数的平衡树即可,直接用SBT即可。
然后把重儿子放到序列的开头算哈希值即可。
为了降低冲突概率,双哈希+base使用原根即可。
进一步降低冲突概率,每一层用不同的原根即可。
当然这些就是细节了。不清楚有没有卡,不写这些应该6K内能写完。
下面的代码不到7.5K 其实是7.49K
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
#define fi first
#define se second
static cs int M1=1e9+7,M2=1e9+9;
static std::mt19937 R(0);
static int get_gr(cs int M){
int phi=M-1;std::vector<int> p;
for(int re i=2;i*i<=phi;++i)
if(phi%i==0){
p.push_back(i);
while(phi%i==0)phi/=i;
}
if(phi>1)p.push_back(phi);phi=M-1;
auto power=[&](int a,int b)->int{
int r=1;for(;b;b>>=1,a=(ll)a*a%M)
(b&1)&&(r=(ll)r*a%M);return r;
};
for(int re gr=2;;++gr){
bool flag=true;
for(int t:p)if(power(gr,phi/t)==1)
{flag=false;break;}if(flag)return gr;
}
}
static cs int g1=get_gr(M1),g2=get_gr(M2);
static int gen(int M,int g){
auto power=[&](int a,int b)->int{
int r=1;for(;b;b>>=1,a=(ll)a*a%M)
(b&1)&&(r=(ll)r*a%M);return r;
};
while(true){int c=R()%(M-2)+1;
if(std::__gcd(c,M-1)==1)
return power(g,c);
}
}
class Key{
private:
int x,y;
public:
Key(){}Key(int _x,int _y):x(_x),y(_y){}
friend Key operator+(cs Key &a,cs Key &b){return Key((a.x+b.x)%M1,(a.y+b.y)%M2);}
friend Key operator-(cs Key &a,cs Key &b){return Key((a.x-b.x+M1)%M1,(a.y-b.y+M2)%M2);}
friend Key operator*(cs Key &a,cs Key &b){return Key((ll)a.x*b.x%M1,(ll)a.y*b.y%M2);}
friend Key &operator+=(Key &a,cs Key &b){return a=a+b;}
friend Key &operator-=(Key &a,cs Key &b){return a=a-b;}
friend Key &operator*=(Key &a,cs Key &b){return a=a*b;}
friend bool operator<(cs Key &a,cs Key &b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
friend bool operator<=(cs Key &a,cs Key &b){return a.x<b.x||(a.x<=b.x&&a.y<=b.y);}
friend bool operator==(cs Key &a,cs Key &b){return a.x==b.x&&a.y==b.y;}
friend bool operator!=(cs Key &a,cs Key &b){return a.x!=b.x||a.y!=b.y;}
};
Key Random(){return Key(gen(M1,g1),gen(M2,g2));}
cs Key key0(0,0),key1(1,1),keyt(233,233);
cs int N=3e5+7;
namespace SBT{
int lc[N],rc[N],siz[N];
cs double alpha=0.55;
Key prod[N],base[N],h[N];
std::pair<Key,int> vl[N];
inline void pushup(int u){
siz[u]=siz[lc[u]]+siz[rc[u]]+1;
prod[u]=key1;h[u]=key0;
if(lc[u]){
h[u]+=h[lc[u]];
prod[u]*=prod[lc[u]];
}
h[u]+=vl[u].fi*prod[u];
prod[u]*=base[u];
if(rc[u]){
h[u]+=h[rc[u]]*prod[u];
prod[u]*=prod[rc[u]];
}
}
inline void Zig(int &u){
int v=lc[u];lc[u]=rc[v],rc[v]=u;
pushup(u),pushup(v),u=v;
}
inline void Zag(int &u){
int v=rc[u];rc[u]=lc[v],lc[v]=u;
pushup(u),pushup(v),u=v;
}
inline void ins(int &u,int v){
if(!u)return pushup(u=v);
if(vl[v]<vl[u]){
ins(lc[u],v);pushup(u);
if(siz[lc[u]]>siz[u]*alpha)Zig(u);
}else {
ins(rc[u],v);pushup(u);
if(siz[rc[u]]>siz[u]*alpha)Zag(u);
}
}
inline void del(int &u,int v){
if(!u)return ;
if(u==v){
if(!lc[u]||!rc[u]){
u=lc[u]|rc[u];
lc[v]=rc[v]=0;
siz[v]=1;
}
else if(siz[rc[u]]>siz[lc[u]]){
Zag(u),del(lc[u],v);
}
else {
Zig(u),del(rc[u],v);
}
if(u)pushup(u);
return ;
}
(vl[v]<vl[u])?del(lc[u],v):del(rc[u],v);pushup(u);
}
inline int count(int u,cs Key &val,int t=0){
if(!u)return 0;
if(vl[u].fi==val){
return 1+(t==1?siz[lc[u]]:count(lc[u],val,2))
+(t==2?siz[rc[u]]:count(rc[u],val,1));
}
if(val<vl[u].fi)return count(lc[u],val,t);
else return count(rc[u],val,t);
}
}
cs int mod=998244353;
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int power(int a,int b){
int r=1;for(;b;b>>=1,a=mul(a,a))
(b&1)&&(r=mul(r,a));return r;
}
int d[N],son[N],inv[N],rt[N],mxd;
Key Base[N],dBase[N],rec[N];
inline int Ins(int u,int v,cs Key &h){
SBT::base[v]=Base[u];
SBT::vl[v]=std::make_pair(h,v);
SBT::pushup(v);rec[v]=h;
int cnt=SBT::count(rt[u],h);
SBT::ins(rt[u],v);return cnt+1;
}
inline int Del(int u,int v){
int cnt=SBT::count(rt[u],rec[v]);
SBT::del(rt[u],v);return inv[cnt];
}
inline int modify(int u,int v,cs Key &newh){
int res=Del(u,v);return mul(res,Ins(u,v,newh));
}
namespace LCT{
int son[N][2],fa[N];
Key h[N],htag[N];
Key coef[N],prod[N];
int siz[N],stag[N];
int ans[N],atag[N];
inline void init(int u){
htag[u]=key0;h[u]=keyt;
stag[u]=0;atag[u]=1;
siz[u]=ans[u]=1;
coef[u]=prod[u]=key1;
}
inline int &lc(int u){return son[u][0];}
inline int &rc(int u){return son[u][1];}
inline void pushup(int u){
prod[u]=coef[u];
if(lc(u))prod[u]*=prod[lc(u)];
if(rc(u))prod[u]*=prod[rc(u)];
}
inline bool isrt(int u){return son[fa[u]][0]!=u&&son[fa[u]][1]!=u;}
inline bool which(int u){return son[fa[u]][1]==u;}
inline void Rotate(int u){
int p=fa[u],pp=fa[p],d=which(u);
if(!isrt(p))son[pp][which(p)]=u;
son[p][d]=son[u][!d],fa[son[p][d]]=p;
son[u][!d]=p,fa[p]=u,fa[u]=pp;
pushup(p),pushup(u);
}
inline void taghash(int u,Key delta){
htag[u]+=delta;
if(rc(u))delta*=prod[rc(u)];
h[u]+=delta;
}
inline void tagans(int u,int delta){
Mul(atag[u],delta);
Mul(ans[u],delta);
}
inline void tagsiz(int u,int delta){
siz[u]+=delta;
stag[u]+=delta;
}
inline void pushdown(int u){
if(htag[u]!=key0){
if(rc(u))taghash(rc(u),htag[u]),htag[u]*=prod[rc(u)];
htag[u]*=coef[u];if(lc(u))taghash(lc(u),htag[u]);htag[u]=key0;
}
if(stag[u]!=0){
if(lc(u))tagsiz(lc(u),stag[u]);
if(rc(u))tagsiz(rc(u),stag[u]);
stag[u]=0;
}
if(atag[u]!=1){
if(lc(u))tagans(lc(u),atag[u]);
if(rc(u))tagans(rc(u),atag[u]);
atag[u]=1;
}
}
int q[N],qn;
inline void Splay(int u){
q[qn=1]=u;for(int re p=u;!isrt(p);p=fa[p])q[++qn]=fa[p];
while(qn)pushdown(q[qn--]);for(int re p;!isrt(u);Rotate(u))
if(!isrt(p=fa[u]))Rotate(which(u)==which(p)?p:u);
}
}
using LCT::h;
using LCT::siz;
using LCT::lc;
using LCT::rc;
using LCT::Splay;
using LCT::pushdown;
using LCT::pushup;
using LCT::taghash;
using LCT::tagsiz;
using LCT::tagans;
int Q,op,ans,pc,n;
inline void updateson(int u,int v,int &ansfac){// v may be the new hson of u
pushdown(u);rc(u)=0;pushup(u);tagsiz(u,1);
int delta=modify(u,v,h[v]);
if(son[u]){
int w=son[u];Splay(w);
if(siz[w]*2<siz[u]){
Mul(delta,Ins(u,w,h[w]));
son[u]=0;
}
}
if(siz[v]*2>=siz[u]){
son[u]=v;Mul(delta,Del(u,v));
}
Mul(ansfac,delta);
tagans(u,ansfac);
Key newh=key0;
if(rt[u])newh=SBT::h[rt[u]]*Base[u]*Base[u];
if(son[u]){
int w=son[u];Splay(w);
newh+=h[w]*Base[u];
}
Key deltah=newh-h[u];
taghash(u,deltah);pushdown(u);
if(son[u]){
int w=son[u];Splay(w);
LCT::coef[w]=Base[u];
pushup(w);pushdown(u);
rc(u)=w;pushup(u);
}
}
inline void update(int u,int ansfac){
int p=u;while(Splay(u),p=LCT::fa[u]){
while(lc(u))u=lc(u);
Splay(u),Splay(p);
updateson(p,u,ansfac);
u=p;
}
}
inline void Addnode(){
int p=gi();if(op)p=(p+ans)%n+1;
LCT::init(++n);d[n]=d[p]+1;
if(d[n]>mxd)mxd=d[n],dBase[mxd]=Random();
Base[n]=dBase[d[n]];LCT::fa[n]=p;
int ansfac=Ins(p,n,LCT::h[n]);
update(n,ansfac);
}
inline void Query(){
int u=gi();if(op)u=(u+ans)%n+1;
Splay(u);cout<<(ans=LCT::ans[u])<<"\n";
pc=0;for(int re tmp=ans;tmp;tmp&=tmp-1)++pc;
}
signed main(){
#ifdef zxyoi
freopen("growing.in","r",stdin);
#endif
Q=gi(),op=gi();
inv[0]=inv[1]=1;for(int re i=2;i<=Q;++i)inv[i]=mul(inv[mod%i],mod-mod/i);
n=1,LCT::init(1);Base[1]=dBase[0]=Random();
while(Q--){
int tp=gi();if(op)tp=(tp+pc)&1;
switch(tp){
case 0:Addnode();break;
case 1:Query();break;
}
}
return 0;
}