其他分享
首页 > 其他分享> > 【数据结构/分块/可持久化 Trie】AcWing 269. Fotile模拟赛L

【数据结构/分块/可持久化 Trie】AcWing 269. Fotile模拟赛L

作者:互联网

分析

因为这题查询的是指定区间 \([l, r]\) 的最大异或子段,我们很难不想到使用可持久化 \(\texttt{trie}\) 来搞。

然而,对于每次查询,如果单纯地使用可持久化 \(\texttt{trie}\),那么必须要枚举右端点进行查询,那么每次查询的复杂度是 \(O(n{\rm {log}} V)\)(\(V\) 为值域大小),承受不住。

在查询上可以直接优化吗?似乎做不到呢。。你会发现没有什么可用的数据结构可以对此进行优化。

那么考虑使用优雅的暴力——分块来进行操作:

最后说说怎么预处理

综上,复杂度为:\(O(\frac{n}{tot}\cdot {\rm log} V + tot \cdot (\frac{n}{tot}) ^ 2 + tot^2 \frac{n}{tot}{\rm log}V)\),如果简单地将 \({\rm log} V\) 看成是一个常数(最多 \(31\)),那么可以发现块长选取为 \(\sqrt n\) 最合适,整个算法复杂度为 \(O(n\sqrt n {\rm log} V)\)

实现

感觉我的码风应该可以被看懂

// Problem: Fotile模拟赛L
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/271/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;

#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define all(x) (x).begin(), (x).end()

#define x first
#define y second
using pii = pair<int, int>;
using ll = long long;

#define int long long

inline void read(int &x){
    int s=0; x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=2e4+50, M=31, BLK=sqrt(N+1);

int n, Q;
int w[N];

struct LTrie{
	int tr[N*M][2];
	int root[N];
	int s[N], mxid[N*M];
	int idx;
	
	int sum(int l, int r){
		return s[r]^s[l-1];
	}
	
	void insert(int i, int k, int p, int q){
		if(k==-1) return mxid[q]=i, void();
		int val=s[i]>>k&1;
		if(p) tr[q][val^1]=tr[p][val^1];
		tr[q][val]=++idx;
		insert(i, k-1, tr[p][val], tr[q][val]);
		mxid[q]=max(mxid[tr[q][0]], mxid[tr[q][1]]);
	}
	
	void build(){
		mxid[0]=-1;
		root[0]=idx=1;
		insert(0, M, 0, root[0]);
		rep(i,1,n) s[i]^=s[i-1];
		
		rep(i,1,n){
			root[i]=++idx;
			insert(i, M, root[i-1], root[i]);
		}
	}
	
	int query(int u, int c, int lim){
		dwn(i,M,0){
			int val=c>>i&1;
			if(mxid[tr[u][val^1]]>=lim) u=tr[u][val^1];
			else u=tr[u][val];
		}
		return s[mxid[u]]^c;
	}
	
	int query(int l, int r){ // fix r and query limit >= l-1
		return query(root[r], s[r], l-1);	
	}
}pre, suf;

int Len;
int tot;
int L[BLK], R[BLK];
int id[N]; // the block id of index

int f[BLK][BLK];

void init(){
	tot=n/Len;
	rep(i,1,tot) L[i]=(i-1)*Len+1, R[i]=i*Len;
	if(R[tot]<n) ++tot, L[tot]=R[tot-1]+1, R[tot]=n;
	rep(i,1,tot) rep(j,L[i],R[i]) id[j]=i;
	// dp
	rep(i,1,tot){
		int l=L[i], r=R[i];
		rep(j,l,r) rep(k,j,r) f[i][i]=max(f[i][i], pre.sum(j, k));
	}
	rep(len,2,tot){
		rep(l,1,tot-len+1){ // l, r is block id
			int r=l+len-1;
			int lx=L[r], rx=R[r];
			rep(i,lx,rx) f[l][r]=max(f[l][r], pre.query(L[l], i));
			f[l][r]=max(f[l][r], f[l][r-1]);
		}
	}
}

int query(int l, int r){
	int res=0;
	int lid=id[l], rid=id[r];
	if(lid==rid){
		rep(i,l,r) res=max(res, pre.query(l, i));
		return res;
	}
	if(lid+1<rid) res=f[lid+1][rid-1];
	rep(i,l,L[lid+1]-1) res=max(res, suf.query(n-r+1, n-i+1));
	rep(i,R[rid-1]+1,r) res=max(res, pre.query(l, i));
	return res;
}

signed main(){
	cin>>n>>Q;
	rep(i,1,n) read(w[i]);
	rep(i,1,n){
		pre.s[i]=w[i];
		suf.s[i]=w[n+1-i];
	}
	
	pre.build(), suf.build();
	
	Len=sqrt(n+1);
	init();
	
	int res=0;
	while(Q--){
		int l, r; read(l), read(r);
		l=(l+res)%n+1;
		r=(r+res)%n+1;
		if(l>r) swap(l, r);
		cout<<(res=query(l, r))<<endl;
	}
	
	return 0;
}

标签:ch,val,Fotile,Trie,tr,tot,int,rm,269
来源: https://www.cnblogs.com/Tenshi/p/16417499.html