最长公共子序列nlogn神算法,线段树换了几种姿势,怎么搞都超时,把他转换成LIS就AC了
A : 3 3 1 1 2 2
B : 3 2 3 1 2 1
B中的每个元素在A中的位置倒序再放入B中可得 {2,1}{6,5}{2,1}{4,3}{6,5}{4,3}
我们发现,B中的每一个大括号取一个数,对应A中的匹配加1,而要使A的标号递增,就把每个括号按递减顺序排列,然后对这个序列求LIS就是答案。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <map> 4 #include <vector> 5 #include <cstring> 6 #include <set> 7 #include <algorithm> 8 #define maxn 200010 9 using namespace std; 10 int t,n,m; 11 int fa[maxn],fb[maxn]; 12 vector<int> za,zb; 13 vector<int> w[10010]; 14 set<int> qa,qb; 15 int v[maxn*5],ct; 16 void init(){ 17 za.clear(),zb.clear(); 18 memset(fa,0,sizeof fa); 19 memset(fb,0,sizeof fb); 20 qa.clear(),qb.clear(); 21 for(int i=0;i<10010;i++) w[i].clear(); 22 } 23 void read(){ 24 scanf("%d%d",&n,&m); 25 int c,x; 26 for(int i=1;i<=2*n*m;i++) qa.insert(i); 27 for(int i=1;i<=2*n*m;i++) qb.insert(i); 28 for(int i=0;i<n*m;i++){ 29 scanf("%d%d",&c,&x); 30 set<int>::iterator at=qa.lower_bound(x); 31 if(at!=qa.end()){ 32 fa[*at]=c; 33 qa.erase(at); 34 } 35 } 36 for(int i=0;i<n*m;i++){ 37 scanf("%d%d",&c,&x); 38 set<int>::iterator at=qb.lower_bound(x); 39 if(at!=qb.end()){ 40 fb[*at]=c; 41 qb.erase(at); 42 } 43 } 44 for(int i=1;i<=2*m*n;i++){ 45 if(fa[i]) za.push_back(fa[i]); 46 } 47 for(int i=0;i<n*m;i++){ 48 w[za[i]].push_back(i+1); 49 } 50 for(int i=1;i<=2*m*n;i++){ 51 if(fb[i]) zb.push_back(fb[i]); 52 } 53 } 54 int gao_LIS(int a[],int len){ 55 int ret=0; 56 int b[maxn]; 57 b[ret++]=a[0]; 58 for(int i=1;i<len;i++){ 59 int x=lower_bound(b,b+ret,a[i])-b; 60 if(x==ret){ 61 b[ret++]=a[i]; 62 }else{ 63 b[x]=a[i]; 64 } 65 } 66 return ret; 67 } 68 void solve(int ca){ 69 ct=0; 70 for(int i=0;i<n*m;i++){ 71 int nn=w[zb[i]].size(); 72 for(int j=nn-1;j>=0;j--){ 73 v[ct++]=w[zb[i]][j]; 74 } 75 } 76 printf("Case #%d: %d ",ca,gao_LIS(v,ct)); 77 } 78 int main(){ 79 scanf("%d",&t); 80 for(int ca=1;ca<=t;ca++){ 81 init(); 82 read(); 83 solve(ca); 84 } 85 return 0; 86 }
还有一种线段树做法,