数据结构1

集合合并

有n个元素,每个元素在不同的集合内,给出n-1个操作合并两个元素所在集合,保证之前不在同一集合。

有m个询问,(x,y)是在第几次操作后第一次位于同一集合。

n<=1e5

题解

操作完之后就是一棵树,任意两点间只有一条简单路径,只要路径上的边都建好就联通,所以就是查路径最大值,边权为是第几次操作。

那么用倍增维护就好了,注意细节。

#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\n",query(x,y));
    }
}
union

最长公共子序列

给出两个长度为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]可还行)

#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;
     }
}
lcs

文件系统

就是模拟创建文件和文件夹,删除文件和文件夹,返回上一级,输出这一级的文件和文件夹。

用map模拟即可,一开始写的map<string,int>,结果错了,就改成了hash,结果是建文件夹写成了==。

然后文件也是这么写的(没发现)

#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!\n");
                else now=tr[now].fa;
            }
            else {//进入 
                if(tr[now].son[1][val]) now=tr[now].son[1][val];
                else printf("No such directory!\n");
            }
        }
        else if(c[0]=='t'){//创建文件 
            if(tr[now].son[0][val]) printf("File already exists!\n");
            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!\n");
                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!\n");
                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!\n");
            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
*/
files

 

posted @ 2019-09-24 18:21  _JSQ  阅读(134)  评论(0编辑  收藏  举报