2022/7/23

142 篇文章 1 订阅
92 篇文章 0 订阅

1263D - Secret Passwords

如果该字符串没有被标记就去遍历他的每一个字母,通过该字母去感染别的字符串,当然别的字符串中的字母也会被该字母感染,最后看看cnt是多少就可以

#include <bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-x))
using namespace std;
const ll mod=10007;
ll n,vis[30],vv[200005];
string s[200005];
vector<ll>v[30];
ll cnt;
void dfs(ll u,ll ind){
    //cout<<u<<" "<<vis[u];
    for(int i=0;i<v[u].size();i++){
        ll x=v[u][i];
        if(vv[x]) continue;
        vv[x]=vv[ind];
        //cout<<x<<" "<<u<<" "<<vv[x]<<" "<<vv[u]<<endl;
        for(int j=0;j<s[x].size();j++){
            if(vis[s[x][j]-'a']) continue;
            vis[s[x][j]-'a']=vis[u];
            //cout<<u<<" "<<s[x][j]<<" "<<vis[u]<<endl;
            dfs(s[x][j]-'a',x);
        }
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>s[i];
        for(int j=0;j<s[i].size();j++)
        v[s[i][j]-'a'].push_back(i);
    }
    cnt=0;
    for(int i=1;i<=n;i++){
        if(vv[i]) continue;
        cnt++;
        vv[i]=cnt;
        for(int j=0;j<s[i].size();j++){
            if(vis[s[i][j]-'a']) continue;
            vis[s[i][j]-'a']=cnt;
            dfs(s[i][j]-'a',i);
        }
    }
    printf("%lld\n",cnt);
    system("pause");
    return 0;
} 

G-Link with Monotonic Subsequence_"蔚来杯"构造

自己的代码写的好丑,实现的方法也不是很对,最关键的地方是每组分成sqrt(n)向上取整个,然后倒着输出就可以,被签到卡住了,不愧是我

#include <bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-x))
using namespace std;
const ll mod=10007;
ll t,n;
int main(){
    scanf("%lld",&t);
    while(t--){
        scanf("%lld",&n);
        ll m=ceil(sqrt(n));
        ll k=n%m;
        for(int i=k;i>=1;i--) printf("%d ",i);
        for(int i=k;i<n;i+=m)
        for(int j=i+m;j>i;j--) printf("%d ",j);
        printf("\n");
    }
    system("pause");
    return 0;
} 

P1967 [NOIP2013 提高组] 货车运输 - 洛谷 重构树

重构树的模板,可以处理从点x到点y所有路径上最大边权的最小值或者最小边权的最大值;丫的我用前向星MLE,用vector就不MLE,淦

 Kruskal重构树——学习笔记_linbinwu123的博客-CSDN博客_kruskal重构树

#include <bits/stdc++.h>
#define ll int
#define lowbit(x) ((x)&(-x))
using namespace std;
const ll mod=10007;
ll n,m,s[20005],val[20005];
ll siz[20005],d[20005],f[20005],top[20005],son[20005];
vector<int> g[20005];

void dfs1(ll u,ll fa){
    siz[u] =1;f[u]=fa;d[u]=d[fa]+1;son[u]=0;
    for(int i=0;i<g[u].size();i++){
        ll j=g[u][i];
        if(j==fa) continue;
        dfs1(j,u);
        siz[u]+=siz[j];
        if(siz[son[u]]<siz[j]) son[u]=j;
    }
}

void dfs2(ll u,ll topx){
    top[u]=topx;
    if(son[u]) dfs2(son[u],topx);
    for(int i=0;i<g[u].size();i++){
        if(g[u][i]!=f[u]&&g[u][i]!=son[u])
        dfs2(g[u][i],g[u][i]);
    }
}
ll lca(ll x,ll y){
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]]) swap(x,y);
        x=f[top[x]];
    }
    return d[x]<d[y] ? x : y;
}
struct node{
    ll u,v,w;
    bool operator<(const node& a)const { return w>a.w; }
    //升序为(u, v)间多条路中最大边权最小值
    //降序为(u, v)间多条路中最小边权最大值
}ed[50005];
ll findd(ll x){return x==s[x]?x:s[x]=findd(s[x]);}
void exkruscal(){
    ll ct=n;
    for(int i=1;i<=(n<<1);i++) s[i]=i,val[i]=-1;
    sort(ed+1,ed+m+1);
    for(int i=1;i<=m;i++){
        ll xx=findd(ed[i].u),yy=findd(ed[i].v);
        if(xx==yy) continue;
        val[++ct]=ed[i].w;
        s[xx]=s[yy]=ct;
        g[xx].push_back(ct), g[ct].push_back(xx);
        g[yy].push_back(ct), g[ct].push_back(yy);
        if(ct>=(n<<1)-1) break;
    }
    for(int i=1;i<=ct;i++){
        if(!siz[i]){
            ll xx=findd(i);
            dfs1(xx,0);dfs2(xx,xx);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w);
    }
    exkruscal();
    ll q; scanf("%d",&q);
    while(q--){
        ll u,v;
        scanf("%d%d",&u,&v);
        if(findd(u)!=findd(v)) printf("-1\n");
        else printf("%d\n",val[lca(u,v)]);
    }
    system("pause");
    return 0;
} 

P2245 星际导航 - 洛谷 | 重构树

这个题算是双倍经验了吧,上一个题是最大边权的最小值,这个题是最小边权的最大值 

#include <bits/stdc++.h>
#define ll int
#define lowbit(x) ((x)&(-x))
using namespace std;
const ll mod=10007;
ll n,m,s[200005],val[200005];
ll siz[200005],d[200005],f[200005],top[200005],son[200005];
vector<int> g[200005];
ll head[50005],cnt;
struct Edge{
    ll from,to,next,w;
}edge[50005];
void addedge(ll from, ll to){
    edge[++cnt].from = from;
    edge[cnt].to = to;
    edge[cnt].next = head[from];
    head[from] = cnt;
}

void dfs1(ll u,ll fa){
    siz[u] =1;f[u]=fa;d[u]=d[fa]+1;son[u]=0;
    for(int i=0;i<g[u].size();i++){
        ll j=g[u][i];
        if(j==fa) continue;
        dfs1(j,u);
        siz[u]+=siz[j];
        if(siz[son[u]]<siz[j]) son[u]=j;
    }
}

void dfs2(ll u,ll topx){
    top[u]=topx;
    if(son[u]) dfs2(son[u],topx);
    for(int i=0;i<g[u].size();i++){
        if(g[u][i]!=f[u]&&g[u][i]!=son[u])
        dfs2(g[u][i],g[u][i]);
    }
}
ll lca(ll x,ll y){
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]]) swap(x,y);
        x=f[top[x]];
    }
    return d[x]<d[y] ? x : y;
}
struct node{
    ll u,v,w;
    bool operator<(const node& a)const { return w<a.w; }
    //升序为(u, v)间多条路中最大边权最小值
    //降序为(u, v)间多条路中最小边权最大值
}ed[300005];
ll findd(ll x){return x==s[x]?x:s[x]=findd(s[x]);}
void exkruscal(){
    ll ct=n;
    for(int i=1;i<=(n<<1);i++) s[i]=i,val[i]=-1;
    sort(ed+1,ed+m+1);
    for(int i=1;i<=m;i++){
        ll xx=findd(ed[i].u),yy=findd(ed[i].v);
        if(xx==yy) continue;
        val[++ct]=ed[i].w;
        s[xx]=s[yy]=ct;
        g[xx].push_back(ct), g[ct].push_back(xx);
        g[yy].push_back(ct), g[ct].push_back(yy);
        if(ct>=(n<<1)-1) break;
    }
    for(int i=1;i<=ct;i++){
        if(!siz[i]){
            ll xx=findd(i);
            dfs1(xx,0);dfs2(xx,xx);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w);
    }
    exkruscal();
    ll q; scanf("%d",&q);
    while(q--){
        ll u,v;
        scanf("%d%d",&u,&v);
        if(findd(u)!=findd(v)) printf("impossible\n");
        else printf("%d\n",val[lca(u,v)]);
    }
    system("pause");
    return 0;
} 

E-水灾_牛客练习赛62 重构树

又是莫名其妙的MLE,这次用前向星才过的,,,好像改了下数组大小就过了,,,

所选的点中,任意两点的最小路径要大于x才不会断开,所以也就是任意两点路径中的最小权值的最大值要小于等于x,这也说明了重构树是一个小根堆,小根堆相隔的越远val值也就越小,所以不用两两求lca会超时,直接算相邻的就可以,用dfn数组记录dfs序,注意d数组不能用来排序,因为也算入边权转化成的点了,虽然不是很懂为啥是要dfs序,但是经过手推之后发现dfs序是对的,应该是和排序和建树的顺序是有关的,但是没想出来原理到底是啥,可能是脑子已经不转了,,,

现在是2022/7/25,再来看一下,如图

用它来建一个小根堆的重构树,按照这样的输入顺序

就会得到如下图的重构树

 

 dfs序是9,5,8,7,6,4,2,3,1,发现除了5,4外都是相邻的,而且5,4也可以看成是某种意义上的相邻,所以dfs序求相邻是正确的

Kruskal重构树——学习笔记_linbinwu123的博客-CSDN博客_kruskal重构树

#include <bits/stdc++.h>
#define ll int
#define lowbit(x) ((x)&(-x))
using namespace std;
const ll MAX=1e6+5;
const ll mod=10007;
ll n,m,q,s[MAX],val[MAX];
ll siz[MAX],d[MAX],dfnt,dfn[MAX],f[MAX],top[MAX],son[MAX];
ll head[MAX],cnt;
struct Edge{
    ll from,to,next,w;
}edge[MAX<<1];
void addedge(ll from, ll to){
    edge[++cnt].from = from;
    edge[cnt].to = to;
    edge[cnt].next = head[from];
    head[from] = cnt;
}
void dfs1(ll u,ll fa){
    dfn[u]=++dfnt;
    siz[u] =1;f[u]=fa;d[u]=d[fa]+1;son[u]=0;
    for(int i=head[u];i;i=edge[i].next){
        ll j=edge[i].to;
        if(j==fa) continue;
        dfs1(j,u);
        siz[u]+=siz[j];
        if(siz[son[u]]<siz[j]) son[u]=j;
    }
}
void dfs2(ll u,ll topx){
    top[u]=topx;
    if(son[u]) dfs2(son[u],topx);
    for(int i=head[u];i;i=edge[i].next){
        if(edge[i].to!=f[u]&&edge[i].to!=son[u])
        dfs2(edge[i].to,edge[i].to);
    }
}
ll lca(ll x,ll y){
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]]) swap(x,y);
        x=f[top[x]];
    }
    return d[x]<d[y] ? x : y;
}
struct node{
    ll u,v,w;
    bool operator<(const node& a)const { return w>a.w; }
    //升序为(u, v)间多条路中最大边权最小值
    //降序为(u, v)间多条路中最小边权最大值
}ed[MAX];
ll findd(ll x){return x==s[x]?x:s[x]=findd(s[x]);}
void exkruscal(){
    ll ct=n;
    for(int i=1;i<=(n<<1);i++) s[i]=i,val[i]=-1;
    sort(ed+1,ed+m+1);
    for(int i=1;i<=m;i++){
        ll xx=findd(ed[i].u),yy=findd(ed[i].v);
        if(xx==yy) continue;
        val[++ct]=ed[i].w;
        s[xx]=s[yy]=ct;
        addedge(ct,xx);addedge(xx,ct);
        addedge(ct,yy);addedge(yy,ct);
        if(ct>=(n<<1)-1) break;
    }
    for(int i=1;i<=ct;i++){
        if(!siz[i]){
            ll xx=findd(i);
            dfs1(xx,0);dfs2(xx,xx);
        }
    }
}
bool cmp(ll a,ll b){
    return dfn[a]<dfn[b];
    //return d[a]<d[b];
}
ll a[MAX];
int main(){
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w);
    }
    exkruscal();
    ll last=0,k;
    //for(int i=1;i<=2*n;i++) cout<<d[i]<<" "<<dfn[i]<<" "<<findd(i)<<endl;;cout<<endl;
    while(q--){
        scanf("%d",&k);
        for(int i=1;i<=k;i++) scanf("%d",&a[i]),a[i]^=last;
        sort(a+1,a+k+1,cmp);
        for(int i=1;i<=k;i++) cout<<i<<" "<<a[i]<<" "<<dfn[a[i]]<<" "<<d[a[i]]<<" cao"<<endl;
        ll ans=0;
        for(int i=2;i<=k;i++){
            ans=max(ans,val[lca(a[i],a[i-1])]);
            cout<<val[lca(a[i],a[i-1])]<<" cc "<<a[i]<<" "<<a[i-1]<<endl;
        }
        printf("%d\n",ans);last=ans;
    }
    system("pause");
    return 0;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killer_queen4804

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值