zoukankan      html  css  js  c++  java
  • 【XSY2773】基因 后缀平衡树 树套树

    题目描述

      有一棵树,每条边上面都有一个字母。每个点还有一个特征值(a_i)

      定义一个节点(i)对应的字符串为从这个点到根的路径上所有边按顺序拼接而成的字符串(s_i)

      有(m)次操作:

    • (0~u~l~r):询问有多少个字符串(s_i)满足(lcp(s_i,s_u)geq l)(a_ileq r)
    • (1~f~a~c):新增一个点,父亲为(f),到父亲的边上的字符为(c)

      强制在线。

      (n,mleq 40000)

    题解

      因为要加新的点而且要强制在线,所以只能用后缀平衡树了。

      然后就会发现这是一道非常水的题了。

      维护后缀平衡树,每个点再维护关键字为这个区间内每个点的特征值的一棵平衡树,也就是树套树。

      后缀平衡树可以做到(O(1))比较大小,但是这题不需要。

      (其实(O(1))求上面那个东西会跑的很快,但是我很懒。)

      时间复杂度:(O((n+m)log^2 (n+m)))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<utility>
    #include<iostream>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    int rd()
    {
    	int s=0,c;
    	while((c=getchar())<'0'||c>'9');
    	s=c-'0';
    	while((c=getchar())>='0'&&c<='9')
    		s=s*10+c-'0';
    	return s;
    }
    void open(const char *s)
    {
    #ifndef ONLINE_JUDGE
    	char str[100];
    	sprintf(str,"%s.in",s);
    	freopen(str,"r",stdin);
    	sprintf(str,"%s.out",s);
    	freopen(str,"w",stdout);
    #endif
    }
    int id(char c)
    {
    	switch (c)
    	{
    		case 'A':return 1;
    		case 'C':return 2;
    		case 'G':return 3;
    		case 'T':return 4;
    	}
    	return 0;
    }
    namespace mempool
    {
    	int a[2000010];
    	int t;
    	void init()
    	{
    		t=2000000;
    		for(int i=1;i<=t;i++)
    			a[i]=i;
    	}
    	int get()
    	{
    		return a[t--];
    	}
    	void push(int x)
    	{
    		a[++t]=x;
    	}
    }
    const ll inf=0x7fffffffffffffffll;
    const ull base=127;
    ull pw[20];
    int n,m;
    int a[100010];
    //ll hs[100010];
    int f[100010][18];
    int d[100010];
    ull h[100010][18];
    int lcp(int x,int y)
    {
    	if(d[x]>d[y])
    		swap(x,y);
    	int s=0;
    	for(int i=16;i>=0;i--)
    		if((1<<i)<=d[x])
    			if(h[x][i]==h[y][i])
    			{
    				x=f[x][i];
    				y=f[y][i];
    				s+=1<<i;
    			}
    	return s;
    }
    int cmp(int x,int y)
    {
    	for(int i=16;i>=0;i--)
    		if((1<<i)<=d[x]&&(1<<i)<=d[y])
    			if(h[x][i]==h[y][i])
    			{
    				x=f[x][i];
    				y=f[y][i];
    			}
    	return (h[x][0]!=h[y][0]?(h[x][0]<h[y][0]?1:-1):0);
    }
    namespace treap
    {
    	struct node
    	{
    		int k;
    		int c[2],s;
    		int v;
    		int f;
    		int l,r;
    	};
    	node a[2000010];
    	int newnode()
    	{
    		int p=mempool::get();
    		a[p].k=rand();
    		a[p].v=a[p].c[0]=a[p].c[1]=a[p].s=a[p].f=a[p].l=a[p].r=0;
    		return p;
    	}
    	void mt(int p)
    	{
    		a[p].s=a[a[p].c[0]].s+a[a[p].c[1]].s+1;
    		a[p].r=(a[p].c[1]?a[a[p].c[1]].r:a[p].v);
    		a[p].l=(a[p].c[0]?a[a[p].c[0]].l:a[p].v);
    	}
    	int ins(int &p,int x,int f=0)
    	{
    		if(!p)
    		{
    			p=newnode();
    			a[p].v=a[p].l=a[p].r=x;
    			a[p].s=1;
    			a[p].f=f;
    			return p;
    		}
    		int y;
    		if(x<=a[p].v)
    			y=ins(a[p].c[0],x);
    		else
    			y=ins(a[p].c[1],x);
    		mt(p);
    		return y;
    	}
    	void rotate(int x)
    	{
    		int p=a[x].f;
    		int q=a[p].f;
    		int ps=(x==a[p].c[1]);
    		int qs=(p==a[q].c[1]);
    		int c=a[x].c[ps^1];
    		if(a[p].f)
    			a[q].c[qs]=x;
    		a[x].c[ps^1]=p;
    		a[p].c[ps]=c;
    		if(c)
    			a[c].f=p;
    		a[p].f=x;
    		a[x].f=q;
    		mt(p);
    		mt(x);
    	}
    	void insert(int &p,int x)
    	{
    		int y=ins(p,x);
    		while(a[y].f&&a[a[y].f].k>a[y].k)
    			rotate(y);
    		while(a[p].f)
    			p=a[p].f;
    	}
    	void del(int &p)
    	{
    		if(a[p].c[0])
    			del(a[p].c[0]);
    		if(a[p].c[1])
    			del(a[p].c[1]);
    		mempool::push(p);
    		p=0;
    	}
    	int query(int p,int v)
    	{
    		if(!p)
    			return 0;
    		if(a[p].l>v)
    			return 0;
    		if(a[p].r<=v)
    			return a[p].s;
    		if(a[p].v<=v)
    			return a[a[p].c[0]].s+1+query(a[p].c[1],v);
    		return query(a[p].c[0],v);
    	}
    	void dfs(int p,int f)
    	{
    		a[p].f=f;
    		if(a[p].c[0])
    			dfs(a[p].c[0],p);
    		if(a[p].c[1])
    			dfs(a[p].c[1],p);
    		mt(p);
    	}
    	int st[100010];
    	void build(int &p,int *e,int l,int r)
    	{
    		int top=0;
    		for(int i=l;i<=r;i++)
    		{
    			int x=newnode();
    			a[x].v=a[x].l=a[x].r=e[i];
    			a[x].s=1;
    			while(top&&a[x].k>a[st[top]].k)
    			{
    				a[x].c[0]=st[top];
    				mt(st[top]);
    				top--;
    			}
    			if(a[x].c[0])
    				a[a[x].c[0]].f=x;
    			if(top)
    			{
    				a[st[top]].c[1]=x;
    				a[x].f=st[top];
    			}
    			st[++top]=x;
    		}
    		p=st[1];
    		while(top)
    		{
    			if(top>1)
    			{
    				a[st[top-1]].c[1]=st[top];
    				a[st[top]].f=st[top-1];
    			}
    			mt(st[top]);
    			top--;
    		}
    //		dfs(p,0);
    	}
    }
    namespace sgt
    {
    	const double alpha=0.75;
    	struct node
    	{
    		int l,r;
    		int ls,rs;
    		int x;
    		int rt;
    		int s;
    	};
    	node a[100010];
    	int rt;
    	int cnt;
    	int *rebuild;
    	void mt(int p)
    	{
    		a[p].s=a[a[p].ls].s+a[a[p].rs].s+1;
    		a[p].l=(a[p].ls?a[a[p].ls].l:a[p].x);
    		a[p].r=(a[p].rs?a[a[p].rs].r:a[p].x);
    	}
    	void ins(int &p,int x)
    	{
    		if(!p)
    		{
    			p=++cnt;
    			a[p].l=a[p].r=x;
    			a[p].ls=a[p].rs=0;
    			a[p].x=x;
    			a[p].rt=0;
    			a[p].s=1;
    			treap::insert(a[p].rt,::a[x]);
    			return;
    		}
    		treap::insert(a[p].rt,::a[x]);
    		if(cmp(x,a[p].x)==1)
    		{
    			ins(a[p].ls,x);
    			mt(p);
    			if(a[a[p].ls].s>a[p].s*alpha)
    				rebuild=&p;
    		}
    		else
    		{
    			ins(a[p].rs,x);
    			mt(p);
    			if(a[a[p].rs].s>a[p].s*alpha)
    				rebuild=&p;
    		}
    	}
    	int tot;
    	int c[100010];
    	int d[100010];
    	void dfs(int &x)
    	{
    		if(a[x].ls)
    			dfs(a[x].ls);
    		c[++tot]=x;
    		d[tot]=a[x].x;
    		if(a[x].rs)
    			dfs(a[x].rs);
    		treap::del(a[x].rt);
    		x=0;
    	}
    	int e[100010];
    	int f[100010];
    	void build(int &p,int l,int r)
    	{
    		if(l>r)
    			return;
    		int mid=(l+r)>>1;
    		p=c[mid];
    		a[p].x=d[mid];
    //		for(int i=l;i<=r;i++)
    //			treap::insert(a[p].rt,::a[d[i]]);
    		build(a[p].ls,l,mid-1);
    		build(a[p].rs,mid+1,r);
    		if(l==r)
    			e[l]=::a[d[l]];
    		else
    		{
    			int v=::a[d[mid]];
    			int i;
    			for(i=mid;i>l&&v<e[i-1];i--)
    				e[i]=e[i-1];
    			e[i]=v;
    			int l1=l,r1=mid+1;
    			int t1=l;
    			while(l1<=mid||r1<=r)
    				if(r1>r||(l1<=mid&&e[l1]<=e[r1]))
    					f[t1++]=e[l1++];
    				else
    					f[t1++]=e[r1++];
    			for(int i=l;i<=r;i++)
    				e[i]=f[i];
    		}
    		treap::build(a[p].rt,e,l,r);
    		mt(p);
    	}
    	void insert(int x)
    	{
    		rebuild=0;
    		ins(rt,x);
    		if(rebuild)
    		{
    			tot=0;
    			dfs(*rebuild);
    			build(*rebuild,1,tot);
    		}
    	}
    	int query(int p,int x,int l,int r)
    	{
    		if(!p)
    			return 0;
    		if(lcp(a[p].x,x)>=l)
    		{
    			if(lcp(a[p].l,x)>=l&&lcp(a[p].r,x)>=l)
    				return treap::query(a[p].rt,r);
    			return query(a[p].ls,x,l,r)+query(a[p].rs,x,l,r)+(::a[a[p].x]<=r?1:0);
    		}
    		int v=cmp(x,a[p].x);
    		int s=0;
    		if(v!=-1)
    			s+=query(a[p].ls,x,l,r);
    		if(v!=1)
    			s+=query(a[p].rs,x,l,r);
    		return s;
    	}
    }
    void add(int x,int y,int v)
    {
    	h[x][0]=v;
    	f[x][0]=y;
    	d[x]=d[y]+1;
    	for(int i=1;i<=16;i++)
    	{
    		f[x][i]=f[f[x][i-1]][i-1];
    		h[x][i]=h[x][i-1]*pw[i-1]+h[f[x][i-1]][i-1];
    	}
    	sgt::insert(x);
    }
    int query(int x,int l,int r)
    {
    	return sgt::query(sgt::rt,x,l,r);
    }
    int main()
    {
    	open("b");
    	srand(time(0));
    	mempool::init();
    	pw[0]=base;
    	for(int i=1;i<=17;i++)
    		pw[i]=pw[i-1]*pw[i-1];
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	d[1]=0;
    	d[0]=-1;
    	char c[2];
    	int x,y,l,r;
    	for(int i=2;i<=n;i++)
    	{
    		scanf("%d%d%s",&x,&y,c);
    		add(y,x,id(c[0]));
    	}
    	int last=1;
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d",&x);
    		if(!x)
    		{
    			scanf("%d%d%d",&x,&l,&r);
    			x^=last;
    			int ans=query(x,l,r);
    			if(!l&&a[1]<=r)
    				ans++;
    			printf("%d
    ",ans);
    			if(ans)
    				last=ans;
    		}
    		else
    		{
    			n++;
    			scanf("%d%d%s",&x,&a[n],c);
    			x^=last;
    			add(n,x,id(c[0]));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    08.Python网络爬虫之图片懒加载技术、selenium和PhantomJS
    07.验证码处理
    Python网络爬虫第三弹《爬取get请求的页面数据》
    设计模式【十】—— 访问者模式
    设计模式【九】—— 模板方法模式/命令模式
    设计模式【八】—— 代理模式
    设计模式【七】—— 外观模式/享元模式
    设计模式【六】—— 装饰者模式/组合模式
    设计模式【五】—— 适配器模式/桥接模式
    设计模式【四】—— 建造者模式
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8573561.html
Copyright © 2011-2022 走看看