• EOJ Monthly 2020.9.F.动态树(线段树套Trie/树状数组套Trie/分块+Trie)


    题目链接


    (Description)
    维护一棵树,有两种操作:
    1.Add x,y,插入一个节点,父节点为(x)边权为(y)
    2.Query x,y,查询起点为(x),终点在(y)的子树中的最大简单路径边权异或和。

    (Solution)
    Sol 1
    先离线求出树的DFS序,以及(val[x])表示(1)号点到(x)的路径权值异或和,每次查询即求一个(y)子树中与(val[x])异或最大的(val[z])
    (y)子树即一个区间,用线段树套Trie就ok了。
    每次(Add)(val[node])插入包含它的所有区间的Trie,每次(Query)求一下区间中与(val[x])异或的最大值。
    复杂度(O(qlog qlog v))

    Sol 2
    依旧离线先求DFS序。注意到 查询其实就是序列上一个区间的查询,在可持久化Trie中用(Trie[r]-Trie[l-1])(size)就可以解决。
    那么修改就应该是前缀的插入Trie,用树状数组套Trie就ok了。查询时(r)(l-1)在树状数组上的所有节点都需要考虑。
    复杂度(O(qlog qlog v)),常数比线段树小很多。(tql)

    Sol 3
    (Sol 2),注意到 查询其实就是序列上一个区间的查询,我们可以分块。
    对每个块建一棵Trie,插入时插入对应块的Trie。查询时对整块查Trie,零散部分直接(O(sqrt n))(O(1))查询。
    设块大小为(s)(Add)次数为(n)(Query)次数为(m),复杂度(O(nlog v+m(frac nslog v+2s))=O(nlog v+msqrt(nlog v))),常数非常非常小。(tttql)

    ps:
    注意1号节点要插入权值0。


    线段树套Trie:

    //1.554s	650.645MB
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define BIT 30
    #define gc() getchar()
    //#define MAXIN 300000
    //#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    typedef long long LL;
    const int N=2e5+5;
    
    int cnt,Enum,H[N],nxt[N],val[N],L[N],R[N];
    //char IN[MAXIN],*SS=IN,*TT=IN;
    struct Queries
    {
    	int opt,x,y;
    }q[N];
    struct TRIE
    {
    	#define S N*19*31
    	int tot,son[S][2];
    	#undef S
    	void Insert(int x,int v)
    	{
    		for(int i=BIT; ~i; --i)
    		{
    			int c=v>>i&1;
    			if(!son[x][c]) son[x][c]=++tot;
    			x=son[x][c];
    		}
    	}
    	int Query(int x,int v)
    	{
    		if(!x) return 0;
    		int res=0;
    		for(int i=BIT; ~i; --i)
    		{
    			int c=(v>>i&1)^1;
    			son[x][c]?res|=1<<i:c^=1;
    			x=son[x][c];
    		}
    		return res;
    	}
    }Trie;
    struct Segment_Tree
    {
    	#define S N*19
    	int root[S];
    	#undef S
    	#define ls rt<<1
    	#define rs rt<<1|1
    	#define lson l,m,ls
    	#define rson m+1,r,rs
    	void Modify(int l,int r,int rt,int L,int R,int v)
    	{
    		if(!root[rt]) root[rt]=++Trie.tot;
    		Trie.Insert(root[rt],v);
    		if(L<=l && r<=R) return;
    		int m=l+r>>1;
    		if(L<=m) Modify(lson,L,R,v);
    		if(m<R) Modify(rson,L,R,v);
    	}
    	int Query(int l,int r,int rt,int L,int R,int v)
    	{
    		if(L<=l && r<=R) return Trie.Query(root[rt],v);
    		int m=l+r>>1;
    		if(L<=m)
    			if(m<R) return std::max(Query(lson,L,R,v),Query(rson,L,R,v));
    			else return Query(lson,L,R,v);
    		return Query(rson,L,R,v);
    	}
    }T;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now;
    }
    inline bool GetOpt()
    {
    	char c=gc();
    	while(!isalpha(c)) c=gc();
    	return c=='Q';
    }
    inline void AE(int u,int v)
    {
    	nxt[v]=H[u], H[u]=v;
    }
    void DFS(int x)
    {
    	static int Index=0;
    	L[x]=++Index;
    	for(int v=H[x]; v; v=nxt[v]) DFS(v);
    	R[x]=Index;
    }
    
    int main()
    {
    	int Q=read(); cnt=1;
    	for(int i=1,x; i<=Q; ++i)
    		switch(GetOpt())
    		{
    			case 0: x=read(),val[++cnt]=val[x]^read(),AE(x,cnt),q[i]=(Queries){0,x,cnt}; break;
    			case 1: x=read(),q[i]=(Queries){1,x,read()}; break;
    		}
    	DFS(1);
    
    #define S 1,cnt,1
    	T.Modify(S,1,1,0);
    	for(int i=1; i<=Q; ++i)
    		switch(q[i].opt)
    		{
    			case 0: T.Modify(S,L[q[i].y],L[q[i].y],val[q[i].y]); break;
    			case 1: printf("%d
    ",T.Query(S,L[q[i].y],R[q[i].y],val[q[i].x])); break;
    		}
    
    	return 0;
    }
    

    树状数组套Trie:

    //1.162s	486.703MB
    #include <cstdio>
    #include <cctype>
    #include <vector>
    #include <algorithm>
    #define BIT 30
    #define gc() getchar()
    //#define MAXIN 300000
    //#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    typedef long long LL;
    const int N=2e5+5;
    
    int cnt,Enum,H[N],nxt[N],val[N],L[N],R[N];
    //char IN[MAXIN],*SS=IN,*TT=IN;
    struct Queries
    {
    	int opt,x,y;
    }q[N];
    struct TRIE
    {
    	#define S N*19*31
    	int tot,son[S][2],sz[S];
    	#undef S
    	void Insert(int x,int v)
    	{
    		++sz[x];
    		for(int i=BIT; ~i; --i)
    		{
    			int c=v>>i&1;
    			if(!son[x][c]) son[x][c]=++tot;
    			x=son[x][c], ++sz[x];
    		}
    	}
    	int Query(int x,int v)
    	{
    		if(!x) return 0;
    		int res=0;
    		for(int i=BIT; ~i; --i)
    		{
    			int c=(v>>i&1)^1;
    			son[x][c]?res|=1<<i:c^=1;
    			x=son[x][c];
    		}
    		return res;
    	}
    }Trie;
    struct Bit
    {
    	int n,root[N];
    	std::vector<int> v1,v2;
    	#define lb(x) (x&-(x))
    	void Modify(int p,int v)
    	{
    		for(; p<=n; p+=lb(p))
    			!root[p]&&(root[p]=++Trie.tot), Trie.Insert(root[p],v);
    	}
    	void GetP(int p,std::vector<int> &vec)
    	{
    		for(; p; p^=lb(p)) vec.push_back(root[p]);
    	}
    	int Query(int l,int r,int v)
    	{
    		std::vector<int>().swap(v1), std::vector<int>().swap(v2);
    		GetP(l-1,v1), GetP(r,v2);
    		int res=0;
    		for(int i=BIT; ~i; --i)
    		{
    			int c=(v>>i&1)^1,s=0;
    			for(auto j:v1) s-=Trie.sz[Trie.son[j][c]];
    			for(auto j:v2) s+=Trie.sz[Trie.son[j][c]];
    			s>0?res|=1<<i:c^=1;
    			for(auto &j:v1) j=Trie.son[j][c];
    			for(auto &j:v2) j=Trie.son[j][c];
    		}
    		return res;
    	}
    }T;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now;
    }
    inline bool GetOpt()
    {
    	char c=gc();
    	while(!isalpha(c)) c=gc();
    	return c=='Q';
    }
    inline void AE(int u,int v)
    {
    	nxt[v]=H[u], H[u]=v;
    }
    void DFS(int x)
    {
    	static int Index=0;
    	L[x]=++Index;
    	for(int v=H[x]; v; v=nxt[v]) DFS(v);
    	R[x]=Index;
    }
    
    int main()
    {
    	int Q=read(); cnt=1;
    	for(int i=1,x; i<=Q; ++i)
    		switch(GetOpt())
    		{
    			case 0: x=read(),val[++cnt]=val[x]^read(),AE(x,cnt),q[i]=(Queries){0,x,cnt}; break;
    			case 1: x=read(),q[i]=(Queries){1,x,read()}; break;
    		}
    	DFS(1);
    
    	T.n=cnt, T.Modify(1,0);
    	for(int i=1; i<=Q; ++i)
    		switch(q[i].opt)
    		{
    			case 0: T.Modify(L[q[i].y],val[q[i].y]); break;
    			case 1: printf("%d
    ",T.Query(L[q[i].y],R[q[i].y],val[q[i].x])); break;
    		}
    
    	return 0;
    }
    
  • 相关阅读:
    rmq +二分暴力 hdu 5726
    8.25 ccpc 比赛总结
    莫比乌斯反演题目总结
    HDU 4848 Wow! Such Conquering! (搜索+floyd)
    Codeforces 982 C Cut 'em all!(DFS)
    Codefoces 986C AND Graph(DFS)
    CodeForces 986A Fair(BFS)
    ACM经验贴
    Kattis A+B Problem(FFT)
    CF E. Porcelain (双向dp)
  • 原文地址:https://www.cnblogs.com/SovietPower/p/13850810.html
Copyright © 2020-2023  润新知