loj6198谢特 后缀数组+并查集+Trie

先把问题放在后缀数组上考虑

已知两个数组a b,求min(a[i],...,a[j])+(b[i]^b[j])的最大值

套路题

初始每个点都是一个小连通块

把a按从大到小的顺序加入,计算当前加入边作为min的贡献:

每次加入会把两个连通块联通,答案就是两边连通块各出一个数能得到的异或和最大值

我:这不是线性基吗

miaom:mdzz,只能有两个数

我:蛤,好难啊,怎么做啊

miaom:Trie啊

我:哦

没了

  1 #include <bits/stdc++.h>
  2 #define N 500001
  3 #define MAX 18
  4 using namespace std;
  5 int NODE,n;char ch;
  6 int a[N],b[N],c[N*MAX][2],size[N],rt[N],lef[N];
  7 pair<int,int> so[N];
  8 int X[N],Y[N],SA[N],Rk[N],Ht[N],v[N];
  9 void GetSA(int a[],int n,int m=256)
 10 {
 11     int *x=X,*y=Y,i,p,j;
 12     memset(v,0,sizeof v);
 13     for(i=1;i<=n;i++)v[x[i]=a[i]]++;
 14     for(i=1;i<=m;i++)v[i]+=v[i-1];
 15     for(i=n;i>=1;i--)SA[v[x[i]]--]=i;
 16     for(i=1;i<=n;i<<=1,m=p)
 17     {
 18         p=0;
 19         memset(v,0,sizeof v);
 20         for(j=n-i+1;j<=n;j++)y[++p]=j;
 21         for(j=1;j<=n;j++)if(SA[j]>i)y[++p]=SA[j]-i;
 22         for(j=1;j<=n;j++)v[x[y[j]]]++;
 23         for(j=1;j<=m;j++)v[j]+=v[j-1];
 24         for(j=n;j>=1;j--)SA[v[x[y[j]]]--]=y[j];
 25         swap(x,y);
 26         p=1;x[SA[1]]=1;
 27         for(j=2;j<=n;j++)
 28             if(y[SA[j-1]]==y[SA[j]]&&y[SA[j-1]+i]==y[SA[j]+i]) x[SA[j]]=p;
 29                 else x[SA[j]]=++p;
 30         if(p>=n)break;
 31     }
 32 }
 33 void GetHt(int a[],int n)
 34 {
 35     int k=0;
 36     for(int i=1;i<=n;i++)Rk[SA[i]]=i;
 37     for(int i=1;i<=n;i++)
 38     {
 39         if(k)k--;
 40         int j=SA[Rk[i]-1];
 41         while(i+k<=n&&j+k<=n&&a[i+k]==a[j+k])k++;
 42         Ht[Rk[i]]=k;
 43     }
 44 }
 45 int build(int x)
 46 {
 47     int rt=++NODE,now=rt;
 48     for(int i=MAX;i>=0;i--)
 49         c[now][(x>>i)&1]=++NODE,now=NODE;
 50     return rt;
 51 }
 52 int que(int x,int y,int z=0)
 53 {
 54     int best=z;
 55     if(c[x][0])
 56          if(c[y][1]) best=que(c[x][0],c[y][1],z*2+1);
 57          else best=que(c[x][0],c[y][0],z*2);
 58     if(c[x][1])
 59         if(c[y][0]) best=max(best,que(c[x][1],c[y][0],z*2+1));
 60         else best=max(best,que(c[x][1],c[y][1],z*2));
 61     return best;
 62 }
 63 void merge(int x,int y)
 64 {
 65     if(c[x][0])
 66          if(c[y][0]) merge(c[x][0],c[y][0]);
 67          else c[y][0]=c[x][0];
 68     if(c[x][1])
 69         if(c[y][1]) merge(c[x][1],c[y][1]);
 70         else c[y][1]=c[x][1];
 71 }
 72 int getfa(int x)
 73 {
 74     if(lef[x]==x) return x;
 75     else return lef[x]=getfa(lef[x]);
 76 }
 77 int main()
 78 {
 79     scanf("%d",&n);
 80     for(ch=getchar();!isalpha(ch);ch=getchar());
 81     for(int i=1;i<=n;i++,ch=getchar())
 82         a[i]=ch;
 83     for(int i=1;i<=n;i++)
 84         scanf("%d",&b[i]);
 85     GetSA(a,n);
 86     GetHt(a,n);
 87     for(int i=1;i<=n;i++)
 88         size[i]=1,lef[i]=i,rt[i]=build(b[SA[i]]);
 89     for(int i=2;i<=n;i++)
 90         so[i-1]=make_pair(n-Ht[i],i);
 91     sort(so+1,so+n);
 92     int ret=0;
 93     for(int i=1;i<n;i++)
 94     {
 95         int x=so[i].second,y=x-1,z=n-so[i].first;
 96         x=getfa(x);y=getfa(y);
 97         if(size[x]<size[y]) swap(x,y);
 98         int bes=que(rt[y],rt[x])+z;
 99         if(bes>ret)
100             ret=bes;
101         merge(rt[y],rt[x]);
102         size[x]+=size[y];
103         lef[y]=x;
104     }
105     printf("%d\n",ret);
106     return 0;
107 } 
时间: 2024-10-12 20:45:44

loj6198谢特 后缀数组+并查集+Trie的相关文章

BZOJ 4199: [Noi2015]品酒大会( 后缀数组 + 并查集 )

求出后缀数组后, 对height排序, 从大到小来处理(r相似必定是0~r-1相似), 并查集维护. 复杂度O(NlogN + Nalpha(N)) ----------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; ty

Uva 12361 File Retrieval 后缀数组+并查集

题意:有F个单词,1 <= F <=60 , 长度<=10^4, 每次可以输入一个字符串,所有包含该字串的单词会形成一个集合. 问最多能形成多少个不同的集合.集合不能为空. 分析:用后缀数组处理.然后首先考虑一个单词形成一个集合的情况,若该单词是其他单词的字串,则该单词显然不会形成一个集合,那么利用后缀数组, 对于每个单词看能否与其他单词有LCP,且LCP 长度为该单词本身长度. 然后就是多个单词形成集合的情况:比较简单的处理方式就是将h数组值相同的下标集中存储,比如h[x] = h[y

[UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集

[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainbow 调制了 n杯鸡尾酒.这 n杯鸡尾酒排成一行,其中第 i杯酒 (1≤i≤n ) 被贴上了一个标签 si ,每个标签都是 26 个小写英文字母之一.设 Str(l,r)表示第 l杯酒到第 r 杯酒的 r−l+1 个标签顺次连接构成的字

【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集

[BZOJ4199][Noi2015]品酒大会 题面:http://www.lydsy.com/JudgeOnline/wttl/thread.php?tid=2144 题解:听说能用SAM?SA默默水过~ 本题的实现还是非常简单的,先求出height数组,然后两杯酒'r'相似就等价于二者中间的height都>=r,于是我们将height排序,从大到小扔进去,那么所有连续的区间中的点对就都是相似的了.维护连续区间可以用并查集.统计点对个数需要维护size,统计最大乘积需要维护最(次)大(小)值,

POJ 3415 Common Substrings 后缀数组+并查集

后缀数组,看到网上很多题解都是单调栈,这里提供一个不是单调栈的做法, 首先将两个串 连接起来求height   求完之后按height值从大往小合并.  height值代表的是  sa[i]和sa[i-1] 的公共前缀长度,那么每次合并就是合并  i和i-1 那么在合并小的时候公共前缀更大的肯定已经都合并在一起,那么就可以直接统计了. #include<iostream> #include<cstdio> #include<algorithm> #include<

BZOJ 4199 [Noi2015]品酒大会:后缀数组 + 并查集

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4199 题意: 给你一个长度为n的字符串s,和一个长为n的数组v. 对于每个整数r∈[0,n-1]: (1)问你有多少对后缀(suffix(i), suffix(j)),满足LCP(suffix(i), suffix(j)) >= r (2)输出mul[r] = max(v[i]*v[j]),其中i,j满足(1)的条件 题解: 先考虑第(1)问. 由于LCP只受连续的一段height中最小

bzoj 4119 后缀数组 + 并查集

并查集合并的时候更新信息.注意a[ i ] 有负的. #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<vector> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second

Uoj #131. 【NOI2015】品酒大会 后缀数组,并查集

#131. [NOI2015]品酒大会 统计 描述 提交 自定义测试 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainbow 调制了 nn 杯鸡尾酒.这 nn 杯鸡尾酒排成一行,其中第 ii 杯酒 (1≤i≤n1in) 被贴上了一个标签 sisi,每个标签都是 2626 个小写英文字母之一.设 Str(l,r)Strlr 表示第 ll 杯酒到第 rr 杯酒的 

【BZOJ-4199】品酒大会 后缀数组 + 并查集合并集合

4199: [Noi2015]品酒大会 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 436  Solved: 243[Submit][Status][Discuss] Description 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainbow 调制了 nn 杯鸡尾酒.这 nn 杯鸡尾酒排成一行,其中第 i