zoukankan      html  css  js  c++  java
  • Codeforces 504E. Misha and LCP on Tree 题解

    题目链接:E. Misha and LCP on Tree

    题目大意:洛谷


    题解:这是我目前写过最难写的集训队作业。Codeforces 中不可多得的卡常题。

    因为是字符串匹配问题,考虑哈希,每一个点维护到祖先的哈希值,然后查询的时候按照是从叶子向根还是从根向叶子分两个拼起来,然后用长链剖分做到 (O(1)) 查询 k 级祖先,二分答案即可,时间复杂度 (O((n+m)log n))。然后等你写完以为时限绰绰有余时,你会发现在 TLE 6 和 TLE 9 之间反复横跳。

    所以你需要一些优化,比如说将 (O(nlog n)-O(log n)) 的倍增求 LCA 改成 (O(nlog n)-O(1)) 的 RMQ 求 LCA,然后加读入输出优化,然后预处理 (log_2 x) 的值等等。(这题的卡常难度对我而言和 Ynoi 有的一拼。

    代码:(fread 的快读板子不是我的,是同校的一位神仙的。最慢点 7971 ms)

    #include <vector>
    #include <cstdio>
    #include <cctype>
    using namespace std;
    namespace io {
    #define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
      const int SIZE = (1 << 21) + 1;
      char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1;
      inline char getc () {return (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++);}
      inline void flush () {fwrite (obuf, 1, oS - obuf, stdout); oS = obuf;}
      inline void putc (char x) {*oS ++ = x; if (oS == oT) flush ();}
      template<class T>
      inline void read(T &x) {
        char ch; int f = 1;
        x = 0;
        while(isspace(ch = getc()));
        if(ch == '-') ch = getc(), f = -1;
        do x = x * 10 + ch - '0'; while(isdigit(ch = getc()));
        x *= f;
      }
      template<class T, class ...Args>
      inline void read(T &x, Args&... args) {read(x); read(args...);}
      template<class T>
      inline void write(T x) {
        static char stk[128];
        int top = 0;
        if(x == 0) {putc('0'); return;}
        if(x < 0) putc('-'), x = -x;
        while(x) stk[top++] = x % 10, x /= 10;
        while(top) putc(stk[--top] + '0');
      }
      template<class T, class ...Args>
      inline void write(T x, Args... args) {write(x); putc(' '); write(args...);}
      inline void space() {putc(' ');}
      inline void endl() {putc('
    ');}
      struct _flush {~_flush() {flush();}} __flush;
    };
    using io::read; using io::write; using io::flush; using io::space; using io::endl; using io::getc; using io::putc;
    
    int quick_power(int a,int b,int Mod){
    	int ans=1;
    	while(b){
    		if(b&1){
    			ans=1ll*ans*a%Mod;
    		}
    		b>>=1;
    		a=1ll*a*a%Mod;
    	}
    	return ans;
    }
    void add(int &x,int y,int Mod){
    	x+=y;
    	if(x>=Mod){
    		x-=Mod;
    	}
    }
    void del(int &x,int y,int Mod){
    	x-=y;
    	if(x<0){
    		x+=Mod;
    	}
    }
    typedef long long ll;
    const int Maxn=300000;
    const int Base[2]={107,59},Mod[2]={1004535809,1000000007};
    int pow_b[2][Maxn+5],inv_b[2][Maxn+5];
    int f[20][Maxn<<1|5];
    int log_2[Maxn<<1|5];
    int dfn[Maxn+5],rnk[Maxn<<1|5],dfn_tot;
    void init(){
    	for(register int i=0;i<2;++i){
    		pow_b[i][0]=1;
    		inv_b[i][0]=1;
    		for(int j=1;j<=Maxn;++j){
    			pow_b[i][j]=1ll*pow_b[i][j-1]*Base[i]%Mod[i];
    			inv_b[i][j]=quick_power(pow_b[i][j],Mod[i]-2,Mod[i]);
    		}
    	}
    	for(register int i=1;(1<<i)<=dfn_tot;++i){
    		for(register int j=1;j+(1<<i)-1<=dfn_tot;++j){
    			f[i][j]=min(f[i-1][j],f[i-1][j+(1<<(i-1))]);
    		}
    	}
    	log_2[1]=0;
    	for(register int i=2;i<=(Maxn<<1);++i){
    		log_2[i]=log_2[i>>1]+1;
    	}
    }
    char s[Maxn+5];
    int head[Maxn+5],arrive[Maxn<<1|5],nxt[Maxn<<1|5],tot;
    inline void add_edge(int from,int to){
    	arrive[++tot]=to;
    	nxt[tot]=head[from];
    	head[from]=tot;
    }
    int n,m;
    int dep[Maxn+5];
    int fa[20][Maxn+5],mx_dep[Maxn+5];
    int root;
    int son[Maxn+5],top[Maxn+5];
    void init_dfs_1(int u){
    	for(register int i=1;fa[i-1][fa[i-1][u]];++i){
    		fa[i][u]=fa[i-1][fa[i-1][u]];
    	}
    	dep[u]=dep[fa[0][u]]+1;
    	mx_dep[u]=1;
    	for(register int i=head[u];i;i=nxt[i]){
    		int v=arrive[i];
    		if(v==fa[0][u]){
    			continue;
    		}
    		fa[0][v]=u;
    		init_dfs_1(v);
    		if(mx_dep[v]+1>mx_dep[u]){
    			mx_dep[u]=mx_dep[v]+1;
    			son[u]=v;
    		}
    	}
    }
    vector<int> lis_up[Maxn+5],lis_down[Maxn+5];
    void init_dfs_2(int u,int tp){
    	lis_down[tp].push_back(u);
    	if(u==tp){
    		int len=0,tmp=u;
    		while(tmp&&len<mx_dep[u]){
    			lis_up[u].push_back(tmp);
    			tmp=fa[0][tmp];
    			len++;
    		}
    	}
    	top[u]=tp;
    	if(son[u]){
    		init_dfs_2(son[u],tp);
    	}
    	for(register int i=head[u];i;i=nxt[i]){
    		int v=arrive[i];
    		if(v==fa[0][u]||v==son[u]){
    			continue;
    		}
    		init_dfs_2(v,v);
    	}
    }
    inline int find_kth(int u,int k){
    	if(k==0){
    		return u;
    	}
    	int tmp=log_2[k];
    	int v=fa[tmp][u];
    	v=top[v];
    	if(dep[v]<=dep[u]-k){
    		return lis_down[v][dep[u]-k-dep[v]];
    	}
    	return lis_up[v][dep[v]-dep[u]+k];
    }
    inline int find_lca(int u,int v){
    	u=dfn[u],v=dfn[v];
    	if(u>v){
    		swap(u,v);
    	}
    	int k=log_2[v-u+1];
    	return rnk[min(f[k][u],f[k][v-(1<<k)+1])];
    }
    int num_up[2][Maxn+5],num_down[2][Maxn+5];
    void init_dfs_3(int t,int u){
    	num_down[t][u]=(1ll*num_down[t][fa[0][u]]*Base[t]+(s[u]-'a'+1))%Mod[t];
    	num_up[t][u]=(num_up[t][fa[0][u]]+1ll*pow_b[t][dep[u]-1]*(s[u]-'a'+1))%Mod[t];
    	for(int i=head[u];i;i=nxt[i]){
    		int v=arrive[i];
    		if(v==fa[0][u]){
    			continue;
    		}
    		init_dfs_3(t,v);
    	}
    }
    inline int find_hash(int t,int u,int v){
    	int ans=0;
    	if(dep[u]>dep[v]){
    		ans=num_up[t][u];
    		ans=(1ll*ans-num_up[t][fa[0][v]]+Mod[t])%Mod[t];
    		ans=1ll*ans*inv_b[t][dep[v]-1]%Mod[t];
    	}
    	else{
    		ans=num_down[t][v];
    		ans=(ans-1ll*num_down[t][fa[0][u]]*pow_b[t][dep[v]-dep[u]+1]%Mod[t]+Mod[t])%Mod[t];
    	}
    	return ans;
    }
    inline int find_hash(int t,int u,int v,int lca,int k){
    	if(dep[u]-dep[lca]>=k){
    		return find_hash(t,u,find_kth(u,k));
    	}
    	int ans;
    	if(u==lca){
    		ans=0;
    	}
    	else{
    		ans=find_hash(t,u,find_kth(u,dep[u]-dep[lca]-1));
    	}
    	k=(dep[u]+dep[v]-(dep[lca]<<1))-k;
    	int tmp=find_hash(t,lca,find_kth(v,k));
    	ans=(1ll*ans*pow_b[t][dep[v]-dep[lca]-k+1]+tmp)%Mod[t];
    	return ans;
    }
    inline int query(int u_1,int v_1,int u_2,int v_2){
    	if(s[u_1]!=s[u_2]){
    		return 0;
    	}
    	int lca_1=find_lca(u_1,v_1),lca_2=find_lca(u_2,v_2);
    	int len=min(dep[u_1]+dep[v_1]-(dep[lca_1]<<1),dep[u_2]+dep[v_2]-(dep[lca_2]<<1));
    	int left=0,right=len;
    	while(left<right){
    		int mid=(left+right+1)>>1;
    		if(find_hash(0,u_1,v_1,lca_1,mid)==find_hash(0,u_2,v_2,lca_2,mid)&&find_hash(1,u_1,v_1,lca_1,mid)==find_hash(1,u_2,v_2,lca_2,mid)){
    			left=mid;
    		}
    		else{
    			right=mid-1;
    		}
    	}
    	return left+1;
    }
    void init_dfs_4(int u){
    	dfn[u]=++dfn_tot;
    	f[0][dfn_tot]=dfn[u];
    	rnk[dfn_tot]=u;
    	for(register int i=head[u];i;i=nxt[i]){
    		int v=arrive[i];
    		if(v==fa[0][u]){
    			continue;
    		}
    		init_dfs_4(v);
    		f[0][++dfn_tot]=dfn[u];
    	}
    }
    int main(){
    //	freopen("input.txt","r",stdin);
    //	freopen("output.txt","w",stdout);
    	read(n);
    	{
    		char c=getc();
    		while(c<'a'||c>'z'){
    			c=getc();
    		}
    		int len=0;
    		while(c>='a'&&c<='z'){
    			s[++len]=c;
    			c=getc();
    		}
    	}
    	for(register int i=1;i<n;++i){
    		int u,v;
    		read(u),read(v);
    		add_edge(u,v);
    		add_edge(v,u);
    	}
    	init_dfs_1(1);
    	init_dfs_2(1,1);
    	init_dfs_4(1);
    	init();
    	init_dfs_3(0,1);
    	init_dfs_3(1,1);
    	read(m);
    	for(register int i=1;i<=m;++i){
    		int u_1,v_1,u_2,v_2;
    		read(u_1),read(v_1),read(u_2),read(v_2);
    		write(query(u_1,v_1,u_2,v_2));
    		putc('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    万字总结:学习MySQL优化原理,这一篇就够了!
    sql中自连接的使用
    SQL 优化原则
    Thumbnailator java图片压缩,加水印,批量生成缩略图
    java使用Thumbnailator处理图片
    Mysql优化原则_小表驱动大表IN和EXISTS的合理利用
    MySQL千万级多表关联SQL语句调优
    了解MySQL联表查询中的驱动表,优化查询,以小表驱动大表
    【explain】MySQL联表查询中的驱动表
    pyCharm最新2018激活码
  • 原文地址:https://www.cnblogs.com/withhope/p/13687340.html
Copyright © 2011-2022 走看看