集合合并
有n个元素,每个元素在不同的集合内,给出n-1个操作合并两个元素所在集合,保证之前不在同一集合。
有m个询问,(x,y)是在第几次操作后第一次位于同一集合。
n<=1e5
题解
操作完之后就是一棵树,任意两点间只有一条简单路径,只要路径上的边都建好就联通,所以就是查路径最大值,边权为是第几次操作。
那么用倍增维护就好了,注意细节。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int maxn=200005; int n,m; int dep[maxn],fa[maxn][25],mx[maxn][25];//mx:从i到走2^j步到达的点的路径最大值 int cnt,head[maxn]; struct edge{ int x,y,val,next; }e[maxn<<1]; template<class T>inline void read(T &x){ x=0;int f=0;char ch=getchar(); while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x= f ? -x : x ; } void add(int x,int y,int val){ e[++cnt]=(edge){x,y,val,head[x]}; head[x]=cnt; } void dfs(int x){ for(int i=head[x];i;i=e[i].next){ int y=e[i].y; if(y==fa[x][0]) continue; dep[y]=dep[x]+1; fa[y][0]=x; mx[y][0]=e[i].val; dfs(y); } } void rmq(){ for(int j=1;j<=20;j++) for(int i=1;i<=n;i++){ fa[i][j]=fa[fa[i][j-1]][j-1]; mx[i][j]=max(mx[i][j-1],mx[fa[i][j-1]][j-1]); } } int query(int x,int y){ if(dep[x]<dep[y]) swap(x,y); int delt=dep[x]-dep[y]; int ret=0; for(int i=0;delt;i++,delt>>=1) if(delt&1){ ret=max(ret,mx[x][i]); x=fa[x][i]; } if(x==y) return ret; for(int i=20;fa[x][0]!=fa[y][0];i--) if(fa[x][i]!=fa[y][i]){ ret=max(ret,mx[x][i]); ret=max(ret,mx[y][i]); x=fa[x][i]; y=fa[y][i]; } return max(ret,max(mx[x][0],mx[y][0])); } int main(){ freopen("union.in","r",stdin); freopen("union.out","w",stdout); read(n);read(m); for(int i=1;i<n;i++){ int x,y;read(x);read(y); add(x,y,i); add(y,x,i); } dfs(1); rmq(); for(int i=1;i<=m;i++){ int x,y; read(x);read(y); printf("%d ",query(x,y)); } }
最长公共子序列
给出两个长度为n的排列,求最长公共子序列。
题解
模板题,将a数组映射到b数组,那么b数组就变成了每个数在a数组中的下标。
然后求lis即可。
维护f数组:长度为i的上升子序列末尾最小是f[i],这个数组是单增的(假设f[i]>f[j]&&i<j,但是长度为j的上升子序列中,选取前i个数,第i个数<f[j]<f[i],不满足定义)
按顺序搞b数组,对于b[i]找f数组中最大的j使得b[i]>f[j],然后组成一个长度为j+1的上升子序列,f[j+1]=b[i](不存在原来的f[j+1]<b[i],不然找到的就是j+1),二分查找
最后看f数组中最大的不为最大值的位置。
注意a和b,还有在二分里面传入的是b[i]的话,就不要写b[x](我写成了a[x]可还行)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn=100005; int n; int a[maxn],mp[maxn],b[maxn],f[maxn]; template<class T>inline void read(T &x){ x=0;int f=0;char ch=getchar(); while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x= f ? -x : x ; } int find(int x){ int l=0,r=n,ans=0; while(l<=r){ int mid=(l+r)>>1; if(x>f[mid]) ans=mid,l=mid+1; else r=mid-1; } return ans; } int main(){ freopen("lcs.in","r",stdin); freopen("lcs.out","w",stdout); read(n); for(int i=1;i<=n;i++){ read(a[i]); mp[a[i]]=i; } for(int i=1;i<=n;i++){ read(b[i]); b[i]=mp[b[i]]; } for(int i=1;i<=n;i++) f[i]=0x3f3f3f; for(int i=1;i<=n;i++){ int x=find(b[i]); f[x+1]=b[i]; } for(int i=n;i;i--) if(f[i]!=0x3f3f3f){ printf("%d",i); return 0; } }
文件系统
就是模拟创建文件和文件夹,删除文件和文件夹,返回上一级,输出这一级的文件和文件夹。
用map模拟即可,一开始写的map<string,int>,结果错了,就改成了hash,结果是建文件夹写成了==。
然后文件也是这么写的(没发现)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define ull unsigned long long const int maxn=505; const ull base=10007; int q,cnt,now; char c[15]; string ch; struct node{ int id,belong; bool operator < (const node a) const {return a.id<id;} }; struct point{ int fa; map<ull,int> son[2];//0:文件 1:文件夹 map<int,string> mp[2]; vector<node> s[2]; }tr[maxn]; ull get(){ ull ret=0; int len=ch.size(); for(int i=0;i<len;i++) ret=ret*base+ch[i]; return ret; } void print(){ priority_queue<node> q,no; for(unsigned int i=0;i<tr[now].s[0].size();i++) q.push(tr[now].s[0][i]); for(unsigned int i=0;i<tr[now].s[1].size();i++) no.push(tr[now].s[1][i]); while(!q.empty()){ while(!no.empty()&&q.top().id==no.top().id) {q.pop();no.pop();} node x=q.top(); q.pop(); cout<<tr[now].mp[x.belong][x.id]<<" "; if(x.belong) cout<<"<D>"; else cout<<"<F>"; putchar(10); } } int main(){ freopen("files.in","r",stdin); freopen("files.out","w",stdout); now=++cnt; scanf("%d",&q); while(q--){ scanf("%s",c); if(c[0]=='l') {print();continue;} cin>>ch; ull val=get(); if(c[0]=='c'){ if(ch[0]=='.'){//退出 if(!tr[now].fa) printf("No parent directory! "); else now=tr[now].fa; } else {//进入 if(tr[now].son[1][val]) now=tr[now].son[1][val]; else printf("No such directory! "); } } else if(c[0]=='t'){//创建文件 if(tr[now].son[0][val]) printf("File already exists! "); else { tr[now].son[0][val]=++cnt; tr[now].mp[0][cnt]=ch; tr[now].s[0].push_back((node){cnt,0}); } } else if(c[0]=='r'){ if(strlen(c)==2) {//删除文件 if(!tr[now].son[0][val]) printf("No such file! "); else { int x=tr[now].son[0][val]; tr[now].son[0][val]=0; tr[now].s[1].push_back((node){x,0}); } } else {//删除文件夹 if(!tr[now].son[1][val]) printf("No such directory! "); else { int x=tr[now].son[1][val]; tr[now].son[1][val]=0; tr[now].s[1].push_back((node){x,1}); } } } else if(c[0]=='m'){//创建文件夹 if(tr[now].son[1][val]) printf("Directory already exists! "); else { tr[now].son[1][val]=++cnt; tr[cnt].fa=now; tr[now].mp[1][cnt]=ch; tr[now].s[0].push_back((node){cnt,1}); } } } } /* 3 mkdir standy touch totalfrank ls */