Educational Codeforces Round 53
F. Choosing Two Paths(CF 1073F)
题目描述
http://codeforces.com/contest/1073/problem/F
题解
其实就是类似树上最长链的做法,从根开始往下搜,如果一个点有多于一个孩子那它就可能作为起点。
统计出每个点的两个最深的孩子作为两个起点,然后在所有合法点钟找出符合题意的最长链就好了。
代码
#include<bits/stdc++.h>
#define N 200010
using namespace std;
int n,A,B,C,D,pos,dep[N],f[N],g[N];
int k,la[N],ff[N*2];
struct info{
int x,y;
bool operator<(const info &p)const{
return x<p.x||(x==p.x&&y<p.y);
}
}res;
struct node{int a,b;}e[N*2];
void add(int a,int b)
{
e[++k]=(node){a,b};ff[k]=la[a];la[a]=k;
e[++k]=(node){b,a};ff[k]=la[b];la[b]=k;
}
void dfs(int x,int fa)
{
int cnt=0;f[x]=g[x]=0;
for(int a=la[x];a;a=ff[a])
{
if(e[a].b==fa)continue;cnt++;
dep[e[a].b]=dep[x]+1;dfs(e[a].b,x);
if(dep[f[e[a].b]]>dep[f[x]])g[x]=f[x],f[x]=f[e[a].b];
else if(dep[f[e[a].b]]>dep[g[x]])g[x]=f[e[a].b];
}
if(!cnt)f[x]=x;
if(cnt>=2)
{
info tmp=(info){dep[x],dep[f[x]]+dep[g[x]]-dep[x]*2};
if(res<tmp)res=tmp,pos=x;
}
}
int main()
{
int a,b;
scanf("%d",&n);
for(int i=1;i<n;i++)scanf("%d%d",&a,&b),add(a,b);
dep[1]=0;res=(info){0,0};
dfs(1,0);A=f[pos];C=g[pos];
dep[pos]=0;res=(info){0,0};
dfs(pos,0);B=f[pos];D=g[pos];
printf("%d %d\n%d %d\n",A,B,C,D);
return 0;
}
G. Yet Another LCP Problem(CF 1073G)
题目描述
http://codeforces.com/contest/1073/problem/G
题解
lcp就是后缀数组中height的区间最小值。所以按照这个思路做就好了。
把a数组和b数组所有数字按照后缀数组的rank排序,从左往右扫一遍,拿个单调栈维护一下最小的height和它覆盖的区间,后再从右往左扫一遍做一样的事情,就好了。
代码能力太差了,这东西写了好久。。。
代码
#include<bits/stdc++.h>
#define N 200010
#define ll long long
using namespace std;
int n,m,Q,a[N],b[N],q[N],p[N];char s[N];ll ans;
int cnt[N],x[N],y[N],t[N],sa[N],g[N][20],rk[N],height[N];
struct info{
int x,tp,k;
bool operator<(const info &p)const{
if(k)return rk[x]<rk[p.x]||(x==p.x&&tp>p.tp);
return rk[x]>rk[p.x]||(x==p.x&&tp<p.tp);
}
}h[N*2];
bool cmp(int *g,int a,int b,int l)
{return g[a]==g[b]&&g[a+l]==g[b+l];}
void get_sa()
{
m=128;
for(int i=1;i<=n;i++)cnt[x[i]=s[i]]++;
for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
for(int i=n;i;i--)sa[cnt[x[i]]--]=i;
for(int j=1,tot=0;tot<=n;m=tot,j<<=1)
{
tot=0;for(int i=n-j+1;i<=n;i++)y[++tot]=i;
for(int i=1;i<=n;i++)if(sa[i]>j)y[++tot]=sa[i]-j;
for(int i=1;i<=n;i++)t[i]=x[y[i]];
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++)cnt[t[i]]++;
for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
for(int i=n;i;i--)sa[cnt[t[i]]--]=y[i];
tot=2;swap(x,y);x[sa[1]]=1;
for(int i=2;i<=n;i++)
x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?tot-1:tot++;
}
}
void get_height()
{
for(int i=1;i<=n;i++)rk[sa[i]]=i;
for(int i=1,j,k=0;i<=n;height[rk[i++]]=k)
for(k=k?k-1:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
}
void get_rmq()
{
memset(g,127,sizeof(g));
for(int i=1;i<=n;i++)g[i][0]=height[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i<=n-(1<<j)+1;i++)
g[i][j]=min(g[i][j-1],g[i+(1<<j-1)][j-1]);
}
int lcp(int x,int y)
{
if(x==y)return n-x+1;
x=rk[x];y=rk[y];
if(x>y)swap(x,y);x++;
int p=log2(y-x+1);
return min(g[x][p],g[y-(1<<p)+1][p]);
}
ll solve(int l1,int l2,int tp)
{
ll sum=0,ans=0;int tot=0,top=0;
for(int i=1;i<=l1;i++)h[++tot]=(info){a[i],0,tp};
for(int i=1;i<=l2;i++)h[++tot]=(info){b[i],1,tp};
sort(h+1,h+tot+1);
for(int i=2,j=h[1].tp;i<=tot;i++)
{
int tmp=lcp(h[i-1].x,h[i].x);
while(top&&tmp<=q[top])sum-=(p[top]-p[top-1])*q[top],top--;
sum+=tmp*(j-p[top]);q[++top]=tmp;p[top]=j;
if(!h[i].tp)ans+=sum;j+=h[i].tp;
}
return ans;
}
int main()
{
int l1,l2;
scanf("%d%d %s",&n,&Q,s+1);
get_sa();get_height();get_rmq();
while(Q--)
{
scanf("%d%d",&l1,&l2);ans=0;
for(int i=1;i<=l1;i++)scanf("%d",&a[i]);
for(int i=1;i<=l2;i++)scanf("%d",&b[i]);
b[0]=1;b[l2+1]=n;
ans+=solve(l1,l2,1);reverse(a,a+l1+2);
reverse(b,b+l2+2);ans+=solve(l1,l2,0);
printf("%I64d\n",ans);
}
return 0;
}