首页 > 其他分享 >【CF207C3】Game with Two Trees

【CF207C3】Game with Two Trees

时间:2023-02-15 20:34:44浏览次数:43  
标签:ch int CF207C3 Trees ++ Game link tot Fo

【CF207C3】Game with Two Trees

Description

有两颗动态加入点的树,每条边有一个字符

每次加入完点后T1中到根的链在T2中的匹配次数之和

Input

一行一个数\(q\)

Output

输出\(q\)行每行一个数表示答案

Sample Input

5
1 1 a
2 1 a
1 2 b
2 1 b
2 3 a

Sample Output

1
3
3
4
7

Data Constraint

\(1\le q\le 10^5\)

Solution

给出一个无脑做法

先对T2建广义SAM,再做DAG链剖分

然后T1中每个点可以在DAG链上倍增+Hash找到对应点

接下来写两颗树状数组

分别支持区间加单点查和区间查单点加

复杂度\(O(q\log^2q)\)

Code

#include<bits/stdc++.h>
using namespace std;
#define Fo(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define mo 998244353
#define N 100010
#define LL long long
#define ls x<<1
#define rs (x<<1)|1

namespace IO{
	const int sz=1<<22;
	char a[sz+5],b[sz+5],*p1=a,*p2=a,*t=b,p[105];
	inline char gc(){
		return p1==p2?(p2=(p1=a)+fread(a,1,sz,stdin),p1==p2?EOF:*p1++):*p1++;
	}
	template<class T> void read(T& x){
		x=0; char c=gc();
		for(;c<'0'||c>'9';c=gc());
		for(;c>='0'&&c<='9';c=gc())
			x=x*10+(c-'0');
	}
	inline void flush(){fwrite(b,1,t-b,stdout),t=b; }
	inline void pc(char x){*t++=x; if(t-b==sz) flush(); }
	template<class T> void write(T x,char c='\n'){
		if(x<0) pc('-'), x=-x;
		if(x==0) pc('0'); int t=0;
		for(;x;x/=10) p[++t]=x%10+'0';
		for(;t;--t) pc(p[t]); pc(c);
	}
	struct F{~F(){flush();}}f;
}
using IO::read;
using IO::write;
using IO::gc;

int mod(int x){return x>=mo?x-mo:x;}

int pw[N*2],ipw[N*2];
int n1,n2,id[N*2];
struct node{int ty,u;char ch;}ask[N*2];
vector<int>e1[N*2],e2[N*2];
int num1[N*2],num2[N*2];
struct Trie{
	int tot,ch[N*2][26];
	int insert(int x,int tr){
		ch[x][tr]?x=ch[x][tr]:x=ch[x][tr]=++tot;
		return x;
	}
	void build(int u,int p){
		id[u]=p;
		for(auto v:e2[u])build(v,insert(p,num2[v]));
	}
}T;
struct SAM{
	vector<int>e[N*2];
	LL s1[N*2],s2[N*2]; 
	int ch[N*2][26],link[N*2],len[N*2],u,rt,tot,lst[N*2];
	int nxt[N*2],pre[N*2],son[N*2],rk[N*2],top[N*2],wh[N*2],num;
	int line[N*2],cnt,d[N*2];
	int g[N*2],pos[N*2];
	int *tg[N*2],*tp[N*2];
	int vis[N*2],sz[N*2];
	int dfn[N*2],siz[N*2],ta;
	int extend(int v,int p){
		int u=++tot;
		for(;v&&!ch[v][p];v=link[v])ch[v][p]=u,len[u]=max(len[u],len[v]+1);
		if(!v)link[u]=rt;
		else if(len[ch[v][p]]==len[v]+1)link[u]=ch[v][p];
		else{
			int clone=++tot,Old=ch[v][p];
			len[clone]=len[v]+1;
			Fo(j,0,25)ch[clone][j]=ch[Old][j];
			link[clone]=link[Old];
			link[Old]=link[u]=clone;
			for(;v&&ch[v][p]==Old;v=link[v])ch[v][p]=clone;
		}
		return u;
	}
	void build(){
		rt=lst[1]=tot=1;
		queue<int>q;
		q.push(1);
		while(!q.empty()){
			int u=q.front();q.pop();
			Fo(i,0,25)if(T.ch[u][i]){
				int v=T.ch[u][i];
				lst[v]=extend(lst[u],i);
				q.push(v);
			}
		}
		Fo(i,1,tot)e[link[i]].push_back(i);
	}
	void dfs(int u){
		dfn[u]=++ta;siz[u]=1;
		for(auto v:e[u])dfs(v),siz[u]+=siz[v];
	}
	void DAG(){
		queue<int>q;
		Fo(i,1,tot) Fo(j,0,25)if(ch[i][j])d[ch[i][j]]++;
		q.push(1);
		while(!q.empty()){
			int u=q.front();q.pop();
			line[++cnt]=u;
			Fo(i,0,25)if(ch[u][i]){
				d[ch[u][i]]--;
				if(!d[ch[u][i]])q.push(ch[u][i]);
			}
		}
		Fd(i,cnt,1){
			int u=line[i];s1[u]++;
			Fo(j,0,25)if(ch[u][j]){
				if(s1[ch[u][j]]>s1[nxt[u]])nxt[u]=ch[u][j];
				s1[u]+=s1[ch[u][j]];
			}
		}
		Fo(i,1,cnt){
			int u=line[i];s2[u]++;
			Fo(j,0,25)if(ch[u][j]){
				if(s2[u]>s2[pre[ch[u][j]]])pre[ch[u][j]]=u;
				s2[ch[u][j]]+=s2[u];
			}
		}
		Fo(i,1,tot) Fo(j,0,25)if(ch[i][j]){
			if(nxt[i]==ch[i][j]&&pre[ch[i][j]]==i)son[i]=ch[i][j],wh[i]=j+1;
		}
		int tmp=0;
		Fo(i,1,tot){
			int u=line[i];
			if(vis[u])continue;
			int v=u;
			sz[u]=1;rk[u]=++num;top[u]=u;
			while(son[v])sz[u]++,v=son[v],rk[v]=++num,top[v]=u;
			tg[u]=g+tmp;
			tp[u]=pos+tmp;
			v=u;
			int val=0;
			Fo(j,1,sz[u]){
				vis[v]=1;
				tg[u][j-1]=val;
				tp[u][j-1]=v;
				val=mod(val+1ll*pw[j-1]*wh[v]%mo);
				v=son[v];
			}
			tmp+=sz[u];
		}
	}
}S;
struct BIT{
	int sum[N*2];
	int lowbit(int x){return -x&x;}
	void change(int x,int y){for(;x<=S.tot;x+=lowbit(x))sum[x]+=y;}
	int query(int x){int res=0;for(;x;x-=lowbit(x))res+=sum[x];return res;}
}T1,T2;

int dep[N*2],fa[N*2][20],val[N*2],q;
LL ans;

int main(){
	pw[0]=ipw[0]=1;
	Fo(i,1,N*2-10){
		pw[i]=37ll*pw[i-1]%mo;
		ipw[i]=242816194ll*ipw[i-1]%mo;
	}
	n1=n2=1;
	read(q);
	Fo(i,1,q){
		int ty,u;char s[3];
		read(ty);read(u);s[1]=gc();
		ask[i]=(node){ty,ty==1?n1+1:n2+1,s[1]};
		if(ty==1){
			n1++;
			fa[n1][0]=u;
			dep[n1]=dep[u]+1;
			e1[u].push_back(n1);
			num1[n1]=s[1]-'a';
		}
		if(ty==2){
			n2++;
			e2[u].push_back(n2);
			num2[n2]=s[1]-'a';
		}
	}
	T.tot=1;
	T.build(1,1);
	S.build();
	S.DAG();
	S.dfs(1);
	Fo(i,1,n1) Fo(j,0,18)fa[i][j+1]=fa[fa[i][j]][j];
	Fo(i,2,n1)val[i]=mod(37ll*val[fa[i][0]]%mo+num1[i]+1);
	T1.change(1,1);T1.change(S.tot+1,-1);
	T2.change(1,1);
	ans=1;
	Fo(i,1,q){
		if(ask[i].ty==1){
			int u=1,wh=ask[i].u,flag=1;
			while(wh!=1){
				int up=S.top[u],lu=S.rk[u]-S.rk[up];
				int res=min(dep[wh],S.sz[up]-lu),tmp=lu;
				Fd(j,19,0)if(res>=(1<<j)){
					if(1ll*mod(val[wh]-1ll*val[fa[wh][j]]*pw[1<<j]%mo+mo)*pw[tmp]%mo==mod(S.tg[up][tmp+(1<<j)]-S.tg[up][tmp]+mo)){
						wh=fa[wh][j];tmp+=1<<j;res-=1<<j;
					}
				}
				u=S.tp[up][tmp];
				if(wh!=1){
					if(!S.ch[u][num1[wh]]){flag=0;break;}
					u=S.ch[u][num1[wh]];
					wh=fa[wh][0];
				}
			}
			if(flag){
				ans+=T2.query(S.dfn[u]+S.siz[u]-1)-T2.query(S.dfn[u]-1);
				T1.change(S.dfn[u],1);T1.change(S.dfn[u]+S.siz[u],-1);
			}
		}else{
			ans+=T1.query(S.dfn[S.lst[id[ask[i].u]]]);
			T2.change(S.dfn[S.lst[id[ask[i].u]]],1);
		}
		write(ans);
	}
	return 0;
}

标签:ch,int,CF207C3,Trees,++,Game,link,tot,Fo
From: https://www.cnblogs.com/AmanoKumiko/p/17124545.html

相关文章

  • hgame2023
    hgame2023week1‍test_ncnc签到‍easy_overflow​​有后门pl=b'a'*0x18+p64(0x40117E)p.sendline(pl)​​close(1)关闭了标准输出首先我们要明白什么是标准输......
  • C、Grid game 【 Codeforces Round #534 (Div. 2) 】
    C、Gridgame题意:给你一个4×4的方格,然后给你一些1×2或者2×1的小方格,当这些方格在一行或者一列的时候会消除掉,问最佳放置位置。思路:QAQ,什么时候思维会变强......
  • Fire Game (FZU 2150)(BFS)
    题解:一开始想错了,以为只要烧完就是那个答案,但是这不是最优的结果,需要每两个点都bfs一遍,找到如果能够全部烧完,找到花费时间最小的,如果不能return-1。在bfs的时候,记录答案......
  • 使用精灵组对精灵成员编队 pygame 230213
    定义精灵成员定义了两个精灵成员说明:Background类是精灵类的子类定义精灵组精灵组添加精灵语法:精灵组.add(精灵成员)批量更新数据语法:精灵组.update()说明:目的是让所有的精灵......
  • 2023Hgame
    2023HgameSharedDiary源代码先放一下constexpress=require('express');constbodyParser=require('body-parser');constsession=require('express-session')......
  • CF917D Stranger Trees
    \(\text{Solution}\)\(\text{havegainedsomanytricks。。。}\)第一步:设恰好重合\(i\)条边的答案为\(f(i)\),至少重合\(i\)条边的答案为\(g(i)\)那么\[g(i)=\s......
  • Hgame-2023-week3-Re
    Hgame2023week3Reverse1.kmusic首先点开.exe文件运行(如果没有安装.netruntime,那么他会提醒你先下载,也可以在这里手动下载)。打开是一个如下界面:点击会有对应......
  • 按下空格发射子弹 pygame 230210
    逻辑捕捉用户按下空格的事件创建一个子弹对象在游戏循环中让子弹往上飞行定义子弹模板按下空格拷备子弹让子弹显示并飞......
  • 不方便的左右移动 pygame 230209
    ......
  • 利用按键元组让飞机飞 pygame 230209
    pressed_tuple=pygame.key.get_pressed()ifpressed_tuple[pygame.K_LEFT]:hero_rect.x-=5ifpressed_tuple[pygame.K_RIGHT]:hero_rect.x+=5ifpressed_tupl......