LimitFlat水题集

· · 个人记录

【模板】快读

这scanf不是能过吗

#include<bits/stdc++.h>
using namespace std;
int n,ans,a;
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a);
        ans=max(ans,a);
    }
    printf("%d",ans);

    return 0;
}

fread 只能读文件

#include<bits/stdc++.h>
using namespace std;
int n,ans,a;
char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf;
inline char gc(){
    if(p1==p2){
        p1=buf;
        p2=buf+fread(buf,1,1000000,stdin);
    }
    if(p1==p2)return EOF;
    return *p1++;
}
inline int read(){
    register int res=0;register char c=gc();
    register bool is=0;
    while(c<'0'||c>'9'){
        if(c=='-')is=1;
        c=gc();
    }
    while(c>='0'&&c<='9'){
        res=(res<<1)+(res<<3)+(c^48);
        c=gc();
    }
    return is?-res:res;
}
int main(){
    n=read();
    for(int i=0;i<n;i++){
        ans=max(ans,read());
    }
    printf("%d",ans);

    return 0;
}

【模板】权值线段树合并

std是错的:

#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=1e6;
struct Node{
    int ls,rs;
    int val,pos;
}tr[MAXN*20*4];
int nodeCnt=0;
void insert(int &p,int l,int r,int x,int val){
    if(!p)p=++nodeCnt;
    if(l==r){
        tr[p].val+=val;
        tr[p].pos=l;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)insert(tr[p].ls,l,mid,x,val);
    else if(x>mid)insert(tr[p].rs,mid+1,r,x,val);
    tr[p].val=max(tr[tr[p].ls].val,tr[tr[p].rs].val);
    tr[p].pos=tr[tr[p].ls].val>=tr[tr[p].rs].val?tr[tr[p].ls].pos:tr[tr[p].rs].pos;
}
int merge(int p,int q,int l,int r){
    if(!p)return q;
    if(!q)return p;
    if(l==r){
        tr[p].val+=tr[q].val;
        tr[p].pos=tr[p].val?l:0;
        return p;
    }
    int mid=(l+r)>>1;
    tr[p].ls=merge(tr[p].ls,tr[q].ls,l,mid);
    tr[p].rs=merge(tr[p].rs,tr[q].rs,mid+1,r);
    tr[p].val=max(tr[tr[p].ls].val,tr[tr[p].rs].val);
    tr[p].pos=tr[tr[p].ls].val>=tr[tr[p].rs].val?tr[tr[p].ls].pos:tr[tr[p].rs].pos;
    return p;
}
int roots[MAXN],rootCnt=0;
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int opt;
        cin>>opt;
        if(opt==1){//新建线段树
            roots[++rootCnt]=++nodeCnt;
        }else if(opt==2){//向某棵线段树中加入值
            int nowRoot,x,num;
            scanf("%d%d%d",&nowRoot,&x,&num);
            insert(roots[nowRoot],1,MAXN,x,num);
        }else if(opt==3){//查询某棵线段树中出现最多的是哪个值
            int nowRoot;
            scanf("%d",&nowRoot);
            cout<<tr[roots[nowRoot]].pos<<endl;
        }else if(opt==4){//合并两棵线段树
            int root1,root2;
            scanf("%d%d",&root1,&root2);
            roots[++rootCnt]=merge(root1,root2,1,MAXN);//这里!!!!
        }
    }
    return 0;
}

【模板】乘法逆元(快速幂)

#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
int n,p;
int poww(int a,int b){
    ll ans=1,tmp=a;
    while(b){
        if(b&1){
            ans*=tmp;
            ans%=p;
        }
        tmp=tmp*tmp;
        tmp%=p;
        b>>=1;
    }
    return ans;
}
int main(){
    //freopen("pow10.in","r",stdin);
    //freopen("pow10.out","w",stdout);
    scanf("%d%d",&n,&p);
    for(int i=1;i<=n;i++){
        ll ans=poww(i,p-2);
        cout<<ans<<endl;
    }
    return 0;
} 

【模板】O(1)快速乘

#include<bits/stdc++.h>
using namespace std;
long long a,b,p;
long long ksc(long long a,long long b,long long p){
    long long fir=a*b;
    long long sec=((long long)((long double)a*b/p))*p;
    return fir-sec;
}
int main(){
    scanf("%lld%lld%lld",&a,&b,&p);
    printf("%lld",ksc(a,b,p));

    return 0;
}

【模板】A*

#include<bits/stdc++.h>
using namespace std;
int n,m,k,a,b;
int dis[1005];
bool vis[1005];
namespace Val{
    int to[200005],ne[200005],w[200005],f[1005],cnt;
    void link(int x,int y,int v){
        to[++cnt]=y;
        ne[cnt]=f[x];
        f[x]=cnt;
        w[cnt]=v;
    }
    void dij(){
        memset(dis,127,sizeof(dis));
        memset(vis,0,sizeof(vis));
        dis[b]=0;
        priority_queue<pair<int,int> > q;
        q.push(make_pair(0,b));
        while(!q.empty()){
            int u=q.top().second;q.pop();
            if(vis[u])continue;
            for(int i=f[u];i;i=ne[i]){
                if(dis[to[i]]>dis[u]+w[i]){
                    dis[to[i]]=dis[u]+w[i];
                    q.push(make_pair(-dis[to[i]],to[i]));
                }
            }
        }
    }
}
/*struct data{
    int x,len;
    long long is;
    data(int a,int b){
        x=a;len=b;is=0;
    }
    bool operator <(const data &b)const{
        if((len+dis[x])^(b.len+dis[b.x]))return len+dis[x]<b.len+dis[b.x];
        return x<b.x;
    }
};*/
namespace Astar{
    int to[200005],ne[200005],w[200005],f[1005],cnt;
    void link(int x,int y,int v){
        to[++cnt]=y;
        ne[cnt]=f[x];
        f[x]=cnt;
        w[cnt]=v;
    }
    void work(){
        priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
        q.push(make_pair(dis[a],a));
        while(!q.empty()){
            int len=q.top().first,u=q.top().second;
            q.pop();len-=dis[u];
//          printf("%d %d\n",u,len); 
            if(u==b&&!--k){
                printf("%d",len);
                return ;
            }
            for(int i=f[u];i;i=ne[i]){
                int v=to[i];
                q.push(make_pair(dis[v]+w[i]+len,v));
            }
        }
        puts("-1");
    }

}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        int x,y,val;
        scanf("%d%d%d",&x,&y,&val);
        Val::link(y,x,val);
        Astar::link(x,y,val);
    }
    scanf("%d%d%d",&a,&b,&k);
    if(a==b)k++;

    Val::dij();
    Astar::work(); 

    return 0;
}

【模板】欧拉回路

#include<bits/stdc++.h>
using namespace std;
int n,m;
int to[200005],ne[200005],f[10005],cnt=1;
bool vis[200005];
void link(int x,int y){
    to[++cnt]=y;
    ne[cnt]=f[x];
    f[x]=cnt;
}
int stk[200005],top,ans[200005],ed;
void eulrd(int x){
    for(int &i=f[x];i;i=ne[i]){
        if(vis[i])continue;
        vis[i]=vis[i^1]=1;
        eulrd(to[i]);
    }
    ans[ed++]=x;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        link(x,y);
        link(y,x);
    }
    eulrd(1);
    for(int i=0;i<ed;i++)printf("%d\n",ans[i]);

    return 0;
}

【模板】矩阵乘法

#include<bits/stdc++.h>
using namespace std;
struct mat{
    int x,y;
    int a[105][105];
    void gets(){
        scanf("%d%d",&x,&y);
    }
    void clear(){
        memset(a,0,sizeof(a));
    }
    void read(){
        for(int j=1;j<=y;j++){
            for(int i=1;i<=x;i++){
                scanf("%d",&a[j][i]);
            }
        }
    }
    void write(){
        for(int j=1;j<=y;j++){
            for(int i=1;i<=x;i++){
                printf("%d ",a[j][i]);
            }
            putchar('\n');
        }
    }
    mat operator *(const mat &b)const{
        mat c;c.clear();
        c.x=b.x;c.y=y;
        for(int i=1;i<=c.x;i++){
            for(int j=1;j<=c.y;j++){
                for(int k=1;k<=x;k++){
                    c.a[j][i]+=a[j][k]*b.a[k][i];
                }
            }
        }
        return c;
    }
}a,b;

int main(){
    a.gets();b.gets();
    a.read();b.read();
//  a.write();b.write(); 
    (a*b).write();
    return 0;
}

【模板】缩点

#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=1e5,MAXM=1e6;
struct Edge{
    int from,to,nxt;
}e[MAXM];
int head[MAXN],edgeCnt=1;
void addEdge(int u,int v){
    e[++edgeCnt].from=u;
    e[edgeCnt].to=v;
    e[edgeCnt].nxt=head[u];
    head[u]=edgeCnt;
}
int dfn[MAXN],low[MAXN],dfnCnt=0;
int stck[MAXN],top=0;
bool inStck[MAXN];
int inScc[MAXN],sccCnt=0;
int pointVal[MAXN];
int sumVal[MAXN];
void tarjan(int x){
    dfn[x]=low[x]=++dfnCnt;
    stck[++top]=x;
    inStck[x]=1;
    for(int i=head[x];i;i=e[i].nxt){
        int nowV=e[i].to;
        if(!dfn[nowV]){
            tarjan(nowV);
            low[x]=min(low[x],low[nowV]);
        }else if(inStck[nowV]){
            low[x]=min(low[x],dfn[nowV]);
        }
    }
    if(low[x]==dfn[x]){
        int y;
        sccCnt++;
        do{
            y=stck[top--];
            inScc[y]=sccCnt;
            inStck[y]=0;//
            sumVal[sccCnt]+=pointVal[y];//
        }while(x!=y);
    }
}
bool vis[MAXN];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&pointVal[i]);
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        addEdge(u,v);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);
    for(int i=1;i<=n;i++){
        if(!vis[inScc[i]]){
            vis[inScc[i]]=1;
            printf("%d\n",sumVal[inScc[i]]);
        }
    }
    return 0;
}

【模板】割边

#include<bits/stdc++.h>
using namespace std;
int to[600005],ne[600005],f[50005],cnt=1;
void link(int x,int y){
    to[++cnt]=y;
    ne[cnt]=f[x];
    f[x]=cnt;
}
int n,m;
int dfn[50005],low[50005];
bool cut[600005];
void tar(int x,int fr){
    if(!dfn[x])dfn[x]=low[x]=++cnt;
    for(int i=f[x];i;i=ne[i]){
        if(i==(fr^1))continue;
        int u=to[i];
        if(!dfn[u]){
            tar(u,i);
            low[x]=min(low[u],low[x]);
            if(low[u]>dfn[x])cut[i]=cut[i^1]=1;
        }
        else low[x]=min(low[x],dfn[u]);
    }

}
int ans;
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        link(x,y);link(y,x);
    }cnt=0;
    for(int i=1;i<=n;i++)if(!dfn[i])tar(i,0);
    for(int i=1;i<=m;i++)if(cut[i<<1])ans++;
    printf("%d",ans);

    return 0;
}

【模板】边双连通分量

#include<bits/stdc++.h>
using namespace std;
int to[600005],ne[600005],f[50005],cnt=1;
void link(int x,int y){
    to[++cnt]=y;
    ne[cnt]=f[x];
    f[x]=cnt;
}
int n,m;
int dfn[50005],low[50005];
bool cut[600005];
void tar(int x,int fr){
    if(!dfn[x])dfn[x]=low[x]=++cnt;
    for(int i=f[x];i;i=ne[i]){
        if(i==(fr^1))continue;
        int u=to[i];
        if(!dfn[u]){
            tar(u,i);
            low[x]=min(low[u],low[x]);
            if(low[u]>dfn[x])cut[i]=cut[i^1]=1;
        }
        else low[x]=min(low[x],dfn[u]);
    }

}
int ans;
int dcc[50005];
void dfs(int x){
    dcc[x]=ans;
    for(int i=f[x];i;i=ne[i]){
        if(cut[i])continue;
        int u=to[i];
        if(!dcc[u]){
            dfs(u);
        }
    }

}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        link(x,y);link(y,x);
    }cnt=0;
    for(int i=1;i<=n;i++)if(!dfn[i])tar(i,0);
    for(int i=1;i<=n;i++)if(!dcc[i])ans++,dfs(i);
    printf("%d",ans);

    return 0;
}

学到的第三种强连通分量求法:

void dfs(int u){
    for(int i = head[u]; i; i = e[i].nxt){
        int v = e[i].v;
        if(!vis[v]){//如果没搜索
            vis[v] = vis[u] + 1;//记录“深度”
            dfs(v);//继续搜
        }
        int fu = anc(u), fv = anc(v);//anc 是并查集函数
        if(vis[fv] > 0){//一定要是搜索中的
            if(vis[fu] < vis[fv]) f[fv] = fu;
            else f[fu] = fv;//注意这里,深度小的为祖先节点
        }
    }
    vis[u] = -1;//标记搜索完
    return;
}

【模板】点双连通分量

#include<bits/stdc++.h>
using namespace std;
const int SIZE = 1e5;
int head[SIZE],ver[SIZE*2],Next[SIZE * 2];
int dfn[SIZE],low[SIZE],stk[SIZE],new_id[SIZE],c[SIZE];
int n,m,tot,num,root,top,cnt;
vector<int> dcc[SIZE];
void add(int x,int y){
    ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
}
void tarjan(int x) {
    dfn[x] = low[x] = ++num;
    stk[++top] = x;
    if(x==root&&head[x]==0){
        dcc[++cnt].push_back(x);
        return;
    }
    for (int i=head[x];i;i =Next[i]) {
        int y=ver[i];
        if (!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
            if (low[y]>=dfn[x]) {
                cnt++;
                for(int z=-1;z!=y;dcc[cnt].push_back(z)){
                    z=stk[top--];
                }
                dcc[cnt].push_back(x);
            }
        }
        else low[x]=min(low[x],dfn[y]);
    }
}

int main() {
    cin >> n >> m;
    tot = 1;
    for (int i = 1; i <= m; i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        if (x==y)continue;
        add(x, y),add(y, x);
    }
    for (int i=1;i<=n;i++)
        if (!dfn[i])root=i,tarjan(i);
    for (int i=1;i<=cnt;i++) {
        for (int j=0;j<dcc[i].size();j++)
            printf("%d ",dcc[i][j]);
        puts("");
    }
    return 0;
}

【模板】Trie树

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int SIZE=1000010;
int trie[SIZE][26],ed[SIZE],tot=1;
void insert(char* str){
    int len=strlen(str),p=1;
    for(int i=0;i<len;i++){
        int ch=str[i]-'a';
        if(!trie[p][ch])trie[p][ch]=++tot;
        p=trie[p][ch];
    }
    ed[p]+=1;
}
int search(char* str){
    int ans=0;
    int len=strlen(str),p=1;
    for(int i=0;i<len;i++){
        int ch=str[i]-'a';
        if(!trie[p][ch])return ans;
        p=trie[p][ch],ans+=ed[p];
    }
    return ans;
}
char str[SIZE];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",&str);
        insert(str);
    }
    for(int i=1;i<=m;i++){
        scanf("%s",&str);
        printf("%d\n",search(str));
    }
    return 0;
}