zoukankan      html  css  js  c++  java
  • LOJ

    题目

    传送门

    解法

    先开始想了半天,觉得 (0,1) 一定是题目的关键突破口。我真傻。

    首先,两个前缀的最长公共后缀长度可以看做 ( ext{parent tree}) 上两个节点(后文节点均在 ( ext{parent tree}) 上)的 ( ext{LCA})len

    那么问题就转化成了一段区间表示的节点两两匹配的 ( ext{LCA})len 的最大值。

    暴力计算一个询问就是 (mathcal O(n^2log n)) 的,我们考虑优化。

    我们从 ( ext{parent tree}) 上来思考。设某子树根为 (rt),它还有子树 (x) 等若干子树,那么显然固定子树 (x) 中的点 (u),它与 (rt) 除了 (x) 外的所有子树内的点的 ( ext{LCA}) 都是 (rt),其 len 是固定的。

    再回到询问区间,我们发现,假如有 ((a,b),(c,d)) 分别有同样的贡献,且 (c<a<b<d),我们只用选择 ((a,b))

    据此我们发现,如果有同样的 len ,其实只用选取在 区间 上离 (u) 最近的两个点来组成点对。

    set 维护节点的子树节点的序列编号,并用启发式合并就可以完成选取点对。点对数量可以用启发式合并时间复杂度来分析,是 (nlog n) 级别的。

    最后将点对按较大的从小到大排序,询问按 (r) 从小到大排序(容易发现 (l) 递增是撤回操作),用树状数组和扫描线维护区间最大值即可(注意树状数组是反着搞的,因为越小的 (l) 反而包含的越多)。

    代码

    #include <cstdio>
    
    #define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
    #define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
    #define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define print(x,y) write(x),putchar(y)
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
    template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
    template <class T> inline T fab(const T x) {return x>0?x:-x;}
    template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
    template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
    template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
    
    #include <set>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    const int maxn=1e5+5;
    
    int n,m,ans[maxn],tot,c[maxn];
    char str[maxn];
    vector <int> e[maxn<<1];
    set <int> :: iterator it,pre,nxt;
    struct Node {
    	int a,b,c;
    	bool operator < (const Node t) const {
    		return b<t.b;
    	}	
    } Pair[maxn*40],q[maxn];
    struct SAM {
    	int cnt,las;
    	set <int> st[maxn<<1];
    	struct node {
    		int to[2],fa,len;
    	} s[maxn<<1];
    	
    	SAM() {cnt=las=1;}
    	
    	void Extend(int i) {
    		int cur=++cnt,p=las,c=str[i]-'0'; s[cur].len=s[las].len+1;
    		for(;p && s[p].to[c]==0;p=s[p].fa) s[p].to[c]=cur;
    		if(!p) s[cur].fa=1;
    		else {
    			int q=s[p].to[c];
    			if(s[q].len==s[p].len+1) s[cur].fa=q;
    			else {
    				int now=++cnt; s[now]=s[q];
    				s[now].len=s[p].len+1;
    				s[q].fa=s[cur].fa=now;
    				for(;p && s[p].to[c]==q;p=s[p].fa) s[p].to[c]=now;
    			}
    		}
    		las=cur; st[cur].insert(i);
    	}
    	
    	void Link() {
    		rep(i,2,cnt) e[s[i].fa].push_back(i);
    	}
    	
    	void dfs(int u) {
    		for(int i=0;i<e[u].size();++i) {
    			int v=e[u][i];
    			dfs(v);
    			if(s[u].len==0) continue;
    			if(st[u].size()<st[v].size()) st[u].swap(st[v]);
    			for(it=st[v].begin();it!=st[v].end();++it) {
    				st[u].insert(*it);
    				pre=nxt=st[u].find(*it); ++nxt;
    				if(pre!=st[u].begin()) --pre,Pair[++tot]=(Node){*pre,*it,s[u].len};
    				if(nxt!=st[u].end()) Pair[++tot]=(Node){*it,*nxt,s[u].len};
    				st[u].erase(*it);
    			}
    			for(it=st[v].begin();it!=st[v].end();++it) st[u].insert(*it);
    		}
    	}
    } mac;
    
    int lowbit(int x) {return x&-x;}
    
    void add(int x,int val) {
    	while(x) c[x]=Max(c[x],val),x-=lowbit(x);
    }
    
    int ask(int x) {
    	int ret=0;
    	while(x<=n) ret=Max(ret,c[x]),x+=lowbit(x);
    	return ret;
    }
    
    int main() {
    	int Pointer=0;
    	n=read(9),m=read(9),scanf("%s",str+1);
    	rep(i,1,n) mac.Extend(i);
    	mac.Link(); mac.dfs(1);
    	rep(i,1,m) q[i].a=read(9),q[i].b=read(9),q[i].c=i;
    	sort(q+1,q+m+1),sort(Pair+1,Pair+tot+1);
    	rep(i,1,m) {
    		while(Pointer<tot && Pair[Pointer+1].b<=q[i].b) ++Pointer,add(Pair[Pointer].a,Pair[Pointer].c);
    		ans[q[i].c]=ask(q[i].a);
    	}
    	rep(i,1,m) print(ans[i],'
    ');
    	return 0;
    }
    
  • 相关阅读:
    【题解】 [yLOI2019] 梅深不见冬
    【题解】[CSP-S2019] Emiya 家今天的饭
    【题解】Acwing400. 太鼓达人
    【题解】[ZJOI2007]最大半连通子图
    【题解】Acwing395. 冗余路径
    【题解】CF487E Tourists
    “𣎴” 这个字存Mysql Incorrect string value: 'xF0xA3x8ExB4' for column 'msg' at row 1
    logminer分析异机db的归档日志(外部文件)
    logminer存储在外部文件(external file)
    logminer分析在线redo log
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14422890.html
Copyright © 2011-2022 走看看