9.30数据结构模拟赛

大意的后果:290分->40分
小小总结一下:
1.并查集按秩合并不要敲太快,不然不知不觉打上去个路径压缩就GG了。
2.把暴力程序的数组复制到正解程序的数组时一定要检查数组开没开够,毕竟暴力是针对30%的数据。。。
3.map等STL的具体用法要搞清楚。

这里写图片描述
题解:并查集按秩合并,然后查一下dep即可。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
const int MAXN=1e5+4;
int n,m,a,b;
int fa[MAXN],rk[MAXN],w[MAXN],dep[MAXN],tim=0;
map<int ,int > mp;
int tot=0;
int find(int x) {
    return fa[x]==x?x:/*fa[x]=*/find(fa[x]);//233......
}
inline void merge(int x,int y) {
    if (rk[x]>rk[y]) x^=y^=x^=y;
    fa[x]=y;
    w[x]=++tim;
    if (rk[x]==rk[y]) ++rk[y];
}
void dfs(int u) {
    if (fa[u]==u) return ;
    dfs(fa[u]);
    dep[u]=dep[fa[u]]+1;
}
inline int query(int u,int v) {
    int ret=0;
    dfs(u),dfs(v);
    if (dep[u]<dep[v]) u^=v^=u^=v;
    while (dep[u]>dep[v]&&u^v) {
        ret=max(ret,w[u]);
        u=fa[u];
    }
    while(u^v) {
        ret=max(ret,max(w[u],w[v]));
        u=fa[u],v=fa[v];
    }
    return ret;
}
int main() {
    freopen("union.in","r",stdin);
    freopen("union.out","w",stdout);
    mp.clear();
    scanf("%d%d",&n,&m);
    for (register int i=1;i<=n;++i) fa[i]=i;
    for (register int i=1;i<n;++i) {
        scanf("%d%d",&a,&b);
        if (!mp.count(a)) mp[a]=++tot,a=tot;
        else a=mp[a];
        if (!mp.count(b)) mp[b]=++tot,b=tot;
        else b=mp[b];
        merge(find(a),find(b));
    }
    for (register int CR7=0;CR7<m;++CR7) {
        scanf("%d%d",&a,&b);
        printf("%d\n",query(mp[a],mp[b]));
    }
    return 0;
}

这里写图片描述
题解:将LCS转成LIS
(1) 对序列B排序
(2) 计算A中每个元素在B中的序号,并构成新序列
(3) 使用LIS的方法计算最长严格递增子序列
(4) 获取最长公共子序列
也可以用树状数组。
复杂度O(nlogn)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e5+4,INF=0x3f3f3f3f;
int n,a[MAXN],c[MAXN],sta[MAXN];
struct B {
    int id,v;
    friend bool operator <(const B &x,const B &y) {
        return x.v<y.v;
    }
}b[MAXN];
inline int read() {
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
int main() {
    freopen("lcs.in","r",stdin);
    freopen("lcs.out","w",stdout);
    n=read();
    for (register int i=1;i<=n;++i) a[i]=read();
    for (register int i=1;i<=n;++i) b[i].v=read(),b[i].id=i;
    sort(b+1,b+n+1);
    for (register int i=1;i<=n;++i) c[i]=b[a[i]].id;
    //LIS
    int len=0,j;
    sta[0]=-INF;
    for (int i=1;i<=n;i++) {
        if (c[i]>sta[len]) j=++len;
        else j=upper_bound(sta+1,sta+len+1,c[i])-sta;
        sta[j]=c[i];
    }
    printf("%d\n",len);
    return 0;
}

这里写图片描述
题解:map乱搞即可,也可以邻接表建图。

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;//<D>==1,<F>==2
#define mkp(x,y) make_pair(x,y)
const int MAXN=105;
int n;
map<pair <string ,int >,int > mp[MAXN];
int tim=1,cur,fa[MAXN];
string nam[MAXN];
int type[MAXN];
int main() {
    freopen("files.in","r",stdin);
    freopen("files.out","w",stdout);
    memset(fa,0,sizeof(fa));
    scanf("%d",&n);
    for (int i=1;i<=n;++i) mp[i].clear();
    cur=1;
    for (int i=1;i<=n;++i) {
        char ss[1002],tt[1002];
        scanf("%s",ss);
        if (ss[0]=='c'&&ss[1]=='d') {
            scanf("%s",tt);
            if (tt[0]^'.') {
                if (mp[cur].count(mkp(tt,1))) cur=mp[cur][mkp(tt,1)];//mp[cur].count(mkp(tt,1))不等于mp[cur][mkp(tt,1)]!!!!!!!!
                else puts("No such directory!");
            }
            else {
                if (fa[cur]) cur=fa[cur];
                else puts("No parent directory!");
            }
        }
        else if (ss[0]=='t') {//创建文件
            scanf("%s",tt);
            if (!mp[cur].count(mkp(tt,2)))
                mp[cur][mkp(tt,2)]=++tim,nam[tim]=tt,type[tim]=2,fa[tim]=cur;
            else puts("File already exists!");
        }
        else if (ss[0]=='m') {//创建文件夹 
            scanf("%s",tt);
            if (!mp[cur].count(mkp(tt,1)))
                mp[cur][mkp(tt,1)]=++tim,nam[tim]=tt,type[tim]=1,fa[tim]=cur;
            else puts("Directory already exists!");
        }
        else if (ss[0]=='r'&&ss[2]=='\0') {//删除文件
            scanf("%s",tt);
            if (!mp[cur].count(mkp(tt,2))) puts("No such file!");
            else {
                int temp=mp[cur][mkp(tt,2)];
                mp[cur].erase(mkp(tt,2)),type[temp]=fa[temp]=0;
            }
        }
        else if (ss[0]=='r'&&ss[2]^'\0') {//删除文件夹
            scanf("%s",tt);
            if (!mp[cur].count(mkp(tt,1))) puts("No such directory!");
            else {
                int temp=mp[cur][mkp(tt,1)];
                mp[cur].erase(mkp(tt,1)),type[temp]=fa[temp]=0;
            }
        }
        else if (ss[0]=='l') {//输出
//          puts("  LIST_ST:");
            for (int i=1;i<=tim;++i) {
                if (type[i]==1&&fa[i]==cur) cout<<nam[i]<<' '<<"<D>\n";
                else if (type[i]==2&&fa[i]==cur) cout<<nam[i]<<' '<<"<F>\n";
            }
//          puts("  LIST_ED:");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值