LOJ #6041. 「雅礼集训 2017 Day7」事情的相似度

我可以大喊一声这就是个套路题吗?

首先看到LCP问题,那么套路的想到SAMSA的做法也有)

LCP的长度是它们在parent树上的LCA(众所周知),所以我们考虑同时统计多个点之间的LCA对

树上问题的话请出万能算法——LCT(这里准确的说应该是实链剖分),我们只需要不停地access就可以找到LCA了

然后怎么统计最后的答案,区间询问用莫队?这里的两个信息(最大值,边的虚实)显然都不能撤销

我们直接大力离线,从左往右把点一个个扔到LCT上,然后对于每个点开一个树状数组维护后缀最大值,由于这里只有加入操作显然是合法的

那么问题就变成怎么维护树状数组了,这个也很套路,在LCT上打懒标记splay的时候下传即可

CODE

#include<cstdio>
#include<cctype>
#include<vector>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=100005;
int n,m,x,len[N<<1],anc[N<<1],id[N],ans[N],L[N],tot; vector <int> v[N];
class FileInputOutput
{
	private:
		static const int S=1<<21;
		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
		#define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
		char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
	public:
		Tp inline void read(T& x)
		{
			x=0; char ch; while (!isdigit(ch=tc()));
			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
		}
		inline void get_digit(int& x)
		{
			char ch; while (!isdigit(ch=tc())); x=ch&15;
		}
		Tp inline void write(T x)
		{
			if (!x) return (void)(pc('0'),pc('\n')); RI ptop=0;
			while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('\n');
		}
		inline void Fend(void)
		{
			fwrite(Fout,1,Ftop,stdout);
		}
		#undef tc
		#undef pc
}F;
class Suffix_Automation
{
	private:
		int ch[N<<1][2],lst;
	public:
		inline Suffix_Automation() { lst=tot=1; }
		inline void expand(CI c,CI pos)
		{
			int now=++tot,fa=lst; id[pos]=lst=now; len[now]=len[fa]+1;
			while (fa&&!ch[fa][c]) ch[fa][c]=now,fa=anc[fa];
			if (!fa) return (void)(anc[now]=1); int x=ch[fa][c];
			if (len[fa]+1==len[x]) return (void)(anc[now]=x);
			int y=++tot; ch[y][0]=ch[x][0]; ch[y][1]=ch[x][1];
			anc[y]=anc[x]; len[y]=len[fa]+1; anc[now]=anc[x]=y;
			while (fa&&ch[fa][c]==x) ch[fa][c]=y,fa=anc[fa];
		}
}SAM;
class Tree_Array
{
	private:
		int mx[N];
		inline void maxer(int& x,CI y)
		{
			if (y>x) x=y;
		}
	public:
		#define lowbit(x) x&-x
		inline void add(RI x,CI y)
		{
			for (;x;x-=lowbit(x)) maxer(mx[x],y);
		}
		inline int get(RI x,int ret=0)
		{
			for (;x<=n;x+=lowbit(x)) maxer(ret,mx[x]); return ret;
		}
		#undef lowbit
}BIT;
class Link_Cut_Tree
{
	private:
		struct splay
		{
			int ch[2],fa,val,tag;
		}node[N<<1]; int stack[N<<1],top;
		#define lc(x) node[x].ch[0]
		#define rc(x) node[x].ch[1]
		#define fa(x) node[x].fa
		#define V(x) node[x].val
		#define T(x) node[x].tag
		inline void pushdown(CI now)
		{
			if (T(now)) T(lc(now))=V(lc(now))=T(rc(now))=V(rc(now))=T(now),T(now)=0;
		}
		inline int identify(CI now)
		{
			return rc(fa(now))==now;
		}
		inline void connect(CI x,CI y,CI d)
		{
			node[fa(x)=y].ch[d]=x;
		}
		inline bool isroot(CI now)
		{
			return lc(fa(now))!=now&&rc(fa(now))!=now;
		}
		inline void rotate(CI now)
		{
			int x=fa(now),y=fa(x),d=identify(now);
			if (!isroot(x)) node[y].ch[identify(x)]=now; fa(now)=y;
			connect(node[now].ch[d^1],x,d); connect(x,now,d^1);
		}
		inline void splay(int now)
		{
			int t=now; while (stack[++top]=t,!isroot(t)) t=fa(t);
			while (top) pushdown(stack[top--]); for (;!isroot(now);rotate(now))
			t=fa(now),!isroot(t)&&(rotate(identify(now)!=identify(t)?now:t),0);
		}
	public:
		inline void init(void)
		{
			for (RI i=1;i<=tot;++i) fa(i)=anc[i];
		}
		inline void access(int x,CI pos,int y=0)
		{
			for (;x;x=fa(y=x)) splay(x),BIT.add(V(x),len[x]),rc(x)=y; T(y)=V(y)=pos;
		}
		#undef lc
		#undef rc
		#undef fa
		#undef V
		#undef T
}LCT;
int main()
{
	//freopen("A.in","r",stdin); freopen("A.out","w",stdout);
	RI i; for (F.read(n),F.read(m),i=1;i<=n;++i)
	F.get_digit(x),SAM.expand(x,i); for (i=1;i<=m;++i)
	F.read(L[i]),F.read(x),v[x].push_back(i);
	for (LCT.init(),i=1;i<=n;++i)
	{
		LCT.access(id[i],i); for (int it:v[i]) ans[it]=BIT.get(L[it]);
	}
	for (i=1;i<=m;++i) F.write(ans[i]); return F.Fend(),0;
}
posted @ 2019-04-08 20:35  hl666  阅读(...)  评论(...编辑  收藏