noip2017酱油记前篇

Posted ck666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了noip2017酱油记前篇相关的知识,希望对你有一定的参考价值。

noip day0

马上就要打酱油了>_<,真是害怕。昨天就整理了一下noip要写的模板

技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=100000+233;
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(0<=ch&&ch<=9){an=an*10+ch-0;ch=getchar();}
    return an*f;
}
struct saber{
int an,l,r;
}t[maxn<<2];
int tt[maxn],a[maxn],b[maxn],dp[maxn],ans,n;
inline void build(int k,int l,int r){
    t[k].l=l;t[k].r=r;
    if(l==r)return ;
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
}
inline int ask(int k,int x,int y){
    int l=t[k].l,r=t[k].r;
    if(l==x&&r==y)return t[k].an;
    int mid=l+r>>1;
    if(mid>=y)return ask(k<<1,x,y);
    else if(x>mid)return ask(k<<1|1,x,y);
    else return max(ask(k<<1,x,mid),ask(k<<1|1,mid+1,y));
}
inline void add(int k,int wi,int fin){
    int l=t[k].l,r=t[k].r;
    if(l==fin&&r==fin){t[k].an=wi;return;}
    int mid=l+r>>1;
    if(mid>=fin)add(k<<1,wi,fin);
    else add(k<<1|1,wi,fin);
    t[k].an=max(t[k<<1].an,t[k<<1|1].an);
}
int main(){
    n=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++)b[i]=read();
    for(int i=1;i<=n;i++)tt[b[i]]=i;
    for(int i=1;i<=n;i++)a[i]=tt[a[i]];
    build(1,1,n);
    for(int i=1;i<=n;i++){
        int x=ask(1,1,a[i]);
        dp[i]=x+1;
        add(1,dp[i],a[i]);
        ans=max(ans,dp[i]);
    }
    cout<<ans;
}
【模板】最长公共子序列

类似导弹拦截


技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<vector>
#define _x .first
#define _y .second
using namespace std;
const int maxn=10000+2333;
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){ch=getchar();}
    while(0<=ch&&ch<=9){an=(an<<3)+(an<<1)+(ch^48);ch=getchar();}
    return an;
}
int tmp;
struct saber{
int l,r,t,id;
}q[maxn];
vector< pair<int,int > > change;

int n,m,a[maxn],block,link[maxn],cntq,cnt,ans[maxn];
int color[maxn*10],size;
char c;
bool operator <(saber x,saber y){return (link[x.l]<link[y.l])||(link[x.l]==link[y.l]&&x.r<y.r)||(link[x.l]==link[y.l]&&x.r==y.r&&x.t<y.t);}

inline void Change(int x,int i){
    if(change[x] _x>=q[i].l&&change[x] _x<=q[i].r){
        color[a[change[x] _x]]--;
        if(color[a[change[x] _x]]==0)tmp--;
        if(color[change[x] _y]==0)tmp++;
        color[change[x] _y]++;
    }
    swap(a[change[x] _x],change[x] _y);
}
int main(){
//    ios::sync_with_stdio(0);
    cin>>n>>m;
    size=sqrt(n);
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=m;i++){
        link[i]=block+1;
        if(!(i%size))block++;
    }
    change.push_back(make_pair(0,0));
    for(int i=1;i<=m;i++){
        cin>>c;
        if(c==R){
            ++cntq;
            int x,y;cin>>x>>y;
            change.push_back( make_pair(x,y) );
        }
        else{
            int x,y;cin>>x>>y;
            q[++cnt]=(saber){x,y,cntq,cnt};
        }
    }
    sort(q+1,q+1+cnt);
    int L=0,R=0,now=0;
    for(int i=1;i<=cnt;i++){
        while(L<q[i].l){color[a[L]]--;if(!color[a[L]])tmp--;L++;}
        while(L>q[i].l){L--;color[a[L]]++;if(color[a[L]]==1)tmp++;}
        while(R<q[i].r){R++;color[a[R]]++;if(color[a[R]]==1)tmp++;}
        while(R>q[i].r){color[a[R]]--;if(color[a[R]]==0)tmp--;R--;}
        while(now<q[i].t){now++,Change(now,i);}
        while(now>q[i].t){Change(now,i);now--;}
        ans[q[i].id]=tmp;
    }
    for(int i=1;i<=cnt;i++)cout<<ans[i]<<"\n";
    return 0;
}
【模板】分块/带修改莫队(数颜色)

分块处理<优雅的暴力>


技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define ll long long
const int mod=1e9+7;
using namespace std;
int n,T;
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(0<=ch&&ch<=9){an=an*10+ch-0;ch=getchar();}
    return an*f;
}
struct saber{
ll a[5][5];
}b,a;
saber operator *(saber A,saber B){
    saber re;
    memset(re.a,0,sizeof re.a);
    for(int k=1;k<=3;k++)
    for(int i=1;i<=3;i++)
    for(int j=1;j<=3;j++)
    re.a[i][j]=(re.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
    return re;
}
inline saber work(saber x,int y){
    saber re;
    re=x;
    while(y){
        if(y&1)re=re*x;
        x=x*x;
        y>>=1;
    }
    return re;
}
int main(){
    b.a[1][3]=1;b.a[2][1]=1;
    b.a[3][3]=1;b.a[3][2]=1;
    a.a[1][1]=1;a.a[1][2]=1;a.a[1][3]=1;
    T=read();
    while(T){
        T--;
        n=read();
        if(n<=3){cout<<"1\n";continue;}
        saber k=work(b,n-4);
        k=a*k;
        cout<<k.a[1][3]<<"\n";
    }
}
P1939 【模板】矩阵加速(数列)

推出矩阵乱搞就好了


技术分享
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<algorithm>
using namespace std;
int read(){
    int an=0,f=1;
    char ch=getchar();
    while(!(0<=ch&&ch<=9)){if(ch==-)f=-f;ch=getchar();}
    while(0<=ch&&ch<=9){an=an*10+ch-0;ch=getchar();}
    return an*f;
}
const int maxn=5099;
const int maxm=200999;
int fa[maxn],cnt,so[maxm];
long long ans;
int m,n,tot;
struct saber{
int from,to,wi;
}b[maxm];
void add(int x,int y,int z){
    cnt++;
    b[cnt].from=x;
    b[cnt].to=y;
    b[cnt].wi=z;
}
bool pai(int x,int y){
    return b[x].wi<b[y].wi;
}
int found(int x){
    if(fa[x]!=x)fa[x]=found(fa[x]);
    return fa[x];
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        int x,y,z;
        x=read();y=read();z=read();
        add(x,y,z);
    }
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++)so[i]=i;
    sort(so+1,so+m+1,pai);
    for(int i=1;i<=m;i++){
        int x=b[so[i]].from;
        int y=b[so[i]].to;
        int f1=found(x);int f2=found(y);
        if(f1!=f2){ans+=b[so[i]].wi;fa[f1]=f2;}
    }
    cout<<ans;
    return 0;
}
【模板】最小生成树

记得路径压缩


技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define IN 599962
int a[IN],c[IN];
int m,n;
int LO(int i){return (-i)&i;}
int  ans(int k){
     int ans=0;
     for(int i=k;i>0;i-=LO(i))ans+=c[i];
     return ans;
}
void F(int k){
    printf("%d",ans(k));
}
void F(int k1,int k2,int k3){
     for(int i=k1;i<=n;i+=LO(i))c[i]+=k3;
     for(int i=k2+1;i<=n;i+=LO(i))c[i]-=k3;
     }
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
      scanf("%d",&a[i]);
      for(int j=i;j<=n;j+=LO(j))c[j]+=a[i];
      int j;j=i+1;
       for(j;j<=n;j+=LO(j))c[j]-=a[i];
      }
    for(int j=1;j<=m;j++){
      int s;
      scanf("%d",&s);
     if(s==1){int k1,k2,k3;
        scanf("%d%d%d",&k1,&k2,&k3);
        F(k1,k2,k3);
     }
     else{int k;
          scanf("%d",&k);
          F(k);
          printf("\n");
     }
    }
    return 0;
}
P3368 【模板】树状数组 2

查分树状数组


技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=10000+2333;
const ll mod=23333333333ll;
const int sand=107;
char ch[maxn];
ll a[maxn];
ll hax(){
    int len=strlen(ch);
    ll re=0;
    for(int i=0;i<len;i++)re=(re*sand+ch[i])%mod;
    return re;
}
int n; 
int main(){
    ios::sync_with_stdio(0);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>ch;
        a[i]=hax();
    }
    sort(a+1,a+1+n);
    int tot=unique(a+1,a+1+n)-a-1;
    cout<<tot;
    return 0;
}
【模板】字符串哈希

哈希判断是否重复,wa了该取模数。O2之后某个溢出哈希就会挂~\(≧▽≦)/~啦啦啦


 

最短路

技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<algorithm>
#include<cstring>
#define _X .first 
#define _Y .second 
#define ll long long
using namespace std;
const int maxn=10000+2333;
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(0<=ch&&ch<=9){an=an*10+ch-0;ch=getchar();}
    return an*f;
}
int n,m,S,cnt;
int f[maxn];
ll dis[maxn];
pair<ll,int>now;
priority_queue<pair<ll,int> >q;
struct saber{
int nex,to,wi;
}b[(500000<<1)+233];
inline void add(int x,int y,int z){
    cnt++;
    b[cnt].wi=z;
    b[cnt].to=y;
    b[cnt].nex=f[x];
    f[x]=cnt;
}
void dij(){
    for(int i=1;i<=n;i++)dis[i]=2147483647;
    dis[S]=0;
    q.push(make_pair(0,-S));
    while(!q.empty()){
        now=q.top();q.pop();
        int x=-now _Y;
        for(int i=f[x];i;i=b[i].nex){
            int v=b[i].to;
            if(dis[v]>dis[x]+b[i].wi){
                dis[v]=dis[x]+b[i].wi;
                q.push(make_pair(-dis[v],-v));
            }
        }
    }
}
int main(){
    n=read();m=read();S=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read(),z=read();
        add(x,y,z);
    }
    dij();
    for(int i=1;i<=n;i++)
    cout<<dis[i]<<" ";
    return 0;
}
dijkstra

传说他稳定

技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<algorithm>
#define ll long long 
using namespace std;
const ll INT=2147483647LL;
ll read(){
    ll an=0,f=1;
    char ch=getchar();
    while(!(0<=ch&&ch<=9)){if(ch==-)f=-1;ch=getchar();}
    while(0<=ch&&ch<=9){an=an*10+ch-0;ch=getchar();}
    return an*f;
}
ll x,y,z;
ll f[10000+99],spf[10000+99],m,n,k,wi[500099],sum;
bool cx[10000+99];
queue<ll>q;
struct saber{
int nex,to;
}b[500099];
void add(ll x,ll y,ll z){
    sum++;
    b[sum].nex=f[x];
    b[sum].to=y;
    f[x]=sum;
    wi[sum]=z;
}
void spfa(){
    while(!q.empty()){
        ll v=q.front();
        q.pop();cx[v]=0;
        for(int i=f[v];i;i=b[i].nex){
            if(spf[b[i].to]>spf[v]+wi[i]){
            spf[b[i].to]=spf[v]+wi[i];
            if(!cx[b[i].to]){
                q.push(b[i].to);
                cx[b[i].to]=1;}
            }
        }
    }
}
int main(){
    n=read();m=read();k=read();
    for(int i=0;i<=n;i++)spf[i]=INT;
    for(int i=1;i<=m;i++){
        x=read();y=read(),z=read();
        add(x,y,z);}
    q.push(k);spf[k]=0;
    cx[k]=1;
    spfa();
    for(int i=1;i<=n;i++)cout<<spf[i]<<" ";
    return 0;
}
SPFA

不知道双向队列那个快?[>_<]


 

线段树模板

技术分享
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring> 
#define ll long long
using namespace std;
const ll maxn=100000+233;
inline ll read(){
    ll an=0,f=1;
    char ch=getchar();
    while(ch<0||9<ch){ch=getchar();}
    while(0<=ch&&ch<=9){an=(an<<1)+(an<<3)+(ch^48);ch=getchar();}
    return an;
}
struct saber{
ll l,r,lazy,sum;
}t[maxn<<4];
ll n,m; 
inline void build(ll k,ll l,ll r){
    t[k].l=l;t[k].r=r;
    if(l==r){t[k].sum=read();return;}
    ll mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
}
inline void change(ll k){
    ll x=t[k].r+1-t[k].l;
    t[k<<1].lazy+=t[k].lazy;
    t[k<<1|1].lazy+=t[k].lazy;
    t[k<<1].sum+=t[k].lazy*(x+1>>1);
    t[k<<1|1].sum+=t[k].lazy*(x>>1);
    t[k].lazy=0;
} 
inline ll ask(ll k,ll x,ll y){
    ll l=t[k].l,r=t[k].r;
    if(t[k].lazy)change(k);
    if(y==r&&l==x){return t[k].sum;}
    ll mid=l+r>>1;
    if(y<=mid)return ask(k<<1,x,y);
    else if(mid<x)return ask(k<<1|1,x,y);
    else return ask(k<<1,x,mid)+ask(k<<1|1,mid+1,y);
}
inline void add(ll k,ll x,ll y,ll wi){
    if(t[k].lazy)change(k);
    ll l=t[k].l,r=t[k].r;
    if(y==r&&l==x){t[k].sum+=(r-l+1)*wi;t[k].lazy+=wi;return;}
    ll mid=l+r>>1;
    if(y<=mid)add(k<<1,x,y,wi);
    else if(mid<x)add(k<<1|1,x,y,wi);
    else {add(k<<1,x,mid,wi);add(k<<1|1,mid+1,y,wi);}
    t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
}
int main(){
    n=read();m=read();
    build(1,1,n);
    for(;m;m--){
        ll pd=read(),x=read(),y=read();
        if(pd==1){
            ll v=read();
            add(1,x,y,v);
        }
        else {
            cout<<ask(1,x,y)<<"\n";
        }
    }
}
线段树
技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath> 
#define ll long long
using namespace std;
inline ll read(){
    ll an=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){ch=getchar();}
    while(0<=ch&&ch<=9){an=(an<<3)+(an<<1)+(ch^48);ch=getchar();}
    return an;
} 
const ll maxn=100000+233;
ll link[maxn],a[maxn],b[3000],size,add[3000],block,n,m,l[3000],r[3000];
int main(){
    ios::sync_with_stdio(0);
    n=read();m=read();
    size=sqrt(n);
    l[1]=1;
    for(ll i=1;i<=n;i++)a[i]=read();
    for(ll i=1;i<=n;i++){
        link[i]=block+1;
        b[block+1]+=a[i];
        if(!(i%size)){
            block++;
            l[block+1]=i+1;
            r[block]=i;
        }
    }
    if(n%size)r[++block]=n;
    for(;m;m--){
        ll pd=read();
        if(pd==1){
            ll L=read(),R=read(),p=read();
            ll chl=link[L],chr=link[R];
            if(chl^chr){
                for(ll i=L;i<=r[chl];i++)a[i]+=p,b[chl]+=p;
                for(ll i=l[chr];i<=R;i++)a[i]+=p,b[chr]+=p;
                for(ll i=chl+1;i<chr;i++)add[i]+=p;
            }
            else{
                for(ll i=L;i<=R;i++)a[i]+=p;
            }
        }
        else {
            ll ans=0,L=read(),R=read();
            ll chl=link[L],chr=link[R];
            if(chl^chr){
                for(ll i=L;i<=r[chl];i++)ans+=add[chl]+a[i];
                for(ll i=l[chr];i<=R;i++)ans+=add[chr]+a[i];
                for(ll i=chl+1;i<chr;i++)ans+=add[i]*(r[i]-l[i]+1)+b[i];
            }
            else{
                for(ll i=L;i<=R;i++)ans+=a[i]+add[i];
            }
            cout<<ans<<"\n";
        }
    }
}
分块

分块还是好写


【模板】树状数组 1

技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define IN 5999620
int a[IN],c[IN];
int LO(int x){return (-x)&x;}
int m,n;
int q,w,e;
void FF(int x,int y){
       for(int k=x;k<=n;k+=LO(k))
       c[k]+=y;
}
int S(int s){int ans=0;
    for(int j=s;j>0;j-=LO(j))
    ans+=c[j];
    return ans;
}
void FFF(int i,int j){
        cout<<S(j)-S(i)<<endl;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){scanf("%d",&a[i]);
     for(int j=i;j<=n;j+=LO(j))
      c[j]+=a[i];}
     for(int i=1;i<=m;i++){
     scanf("%d%d%d",&q,&w,&e);
      if(q==1)FF(w,e);
      else FFF(w-1,e);
     }
     return 0;
}
树状数组

就是2去掉差分


【模板】堆

手打堆

技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(0<=ch&&ch<=9){an=(an<<3)+(an<<1)+ch-48;ch=getchar();}
    return an*f;
}
const int maxn=100000+23;
using namespace std;
int q;
int t[maxn],tot;
inline void add(int x){
    tot++;
    t[tot]=x;
    for(int i=tot,j=i>>1;j;i=j,j=i>>1){
        if(t[j]>t[i])swap(t[i],t[j]);
    }
}
inline void pop(){
    t[1]=t[tot];tot--;
    for(int i=1,j=i<<1;j<=tot;i=j,j=i<<1){
        if(j+1<=tot&&t[j+1]<t[j])
        ++j;
        if(t[i]<t[j])break;
        else swap(t[i],t[j]);
    }
}
inline int getans(){
    return t[1];
}
int main(){
    q=read();
    ios::sync_with_stdio(0);
    while(q){
        q--;
        int x=read();
        if(x==1)add( read() );
        else if(x==2)cout<<getans()<<"\n";
        else pop();
    }
}

【模板】最近公共祖先(LCA)

技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
int read(){
    int an=0,f=1;
    char ch=getchar();
    while(!(0<=ch&&ch<=9)){if(ch==-)f=-f;ch=getchar();}
    while(0<=ch&&ch<=9){an=an*10+ch-0;ch=getchar();}
    return f*an;
}
const int maxn=500000+999;
int n,m,s,cnt;
int f[maxn],fa[maxn][25],deep[maxn];
bool vis[maxn];
int x,y;
struct saber{
int nex,to;
}b[maxn*2];
void add(int x,int y){
    cnt++;
    b[cnt].nex=f[x];
    b[cnt].to=y;
    f[x]=cnt;}
void dfs(int x){
    vis[x]=1;
    for(int i=f[x];i;i=b[i].nex){
        int v=b[i].to;
        if(!vis[v]){
            fa[v][0]=x;deep[v]=deep[x]+1;
        for(int j=1;j<=20;j++){
            if(!fa[fa[v][j-1]][j-1])break;
            fa[v][j]=fa[fa[v][j-1]][j-1];}
            dfs(v);
        }
    }
}
int lca(int u,int v){
    if(deep[u]>deep[v])swap(u,v);
    for(int i=20;i>=0;i--)
        if(deep[fa[v][i]]>=deep[u])v=fa[v][i];
    if(u==v)return u;
    for(int i=20;i>=0;i--)
        if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
    if(u==v)return u;
    return fa[u][0];
}
void Lca(int x,int y){
    int ans=lca(x,y);
    printf("%d\n",ans);
}
int main(){
    n=read();m=read();s=read();
    for(int i=1;i<n;i++){
        x=read();y=read();
        add(x,y);add(y,x);}
    deep[s]=1;
    dfs(s);
    for(int i=1;i<=m;i++){
        x=read();y=read();
        Lca(x,y);}
    return 0;
}
倍增
技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<algorithm>
using namespace std;
int read(){
    int an=0,f=1;char ch=getchar();
    while(!(0<=ch&&ch<=9)){if(ch==-)f=-f;ch=getchar();}
    while(0<=ch&&ch<=9){an=an*10+ch-0;ch=getchar();}
    return an*f;
}
int n,m,s,cnt,qf[500099],f[500099],fa[500099],ans[500099<<1];
int x,y;
bool vis[500099];
int found(int x){
    if(fa[x]!=x)fa[x]=found(fa[x]);
    return fa[x];}
struct saber{
int to,nex;
}b[500099<<1];
struct question{
int to,nex;
}qu[500099<<1];
void add(int x,int y){
    cnt++;b[cnt].to=y;
    b[cnt].nex=f[x];f[x]=cnt;
}
void add(int x,int y,int z){
    qu[z].to=y;
    qu[z].nex=qf[x];
    qf[x]=z;
}
void dfs(int x){
    fa[x]=x;vis[x]=1;
    for(int i=f[x];i;i=b[i].nex){
        int v=b[i].to;
        if(!vis[v]){
            dfs(v);
            fa[v]=x;
        }
    }
    for(int i=qf[x];i;i=qu[i].nex){
        int v=qu[i].to;
        if(vis[v]){
            ans[i]=found(v);
            if(i&1)ans[i+1]=ans[i];
            else ans[i-1]=ans[i];
        }
    }
}
int main(){
    n=read();m=read();s=read();
    for(int i=1;i<n;i++){
        int x,y;x=read();y=read();
        add(x,y);add(y,x);
    }
    for(int i=1;i<=m;i++){
        x=read();y=read();
        add(x,y,(i<<1)-1);add(y,x,(i<<1));
    }
    dfs(s);
    for(int i=1;i<=m;i++){
        printf("%d\n",ans[i<<1]);}
    return 0;
}
tarjian

【模板】网络最大流

技术分享
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring> 
const int maxn=100000+2333;
const int maxm=100000+99999;
const int INT=1e7;
using namespace std;
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<0||9<ch){ch=getchar();}
    while(0<=ch&&ch<=9){an=(an<<1)+(an<<3)+(ch^48);ch=getchar();}
    return an;
}
int f[maxn],S,T,n,m,cnt=1;
struct saber{
int wi,nex,to;
}b[maxn<<2];
inline void add(int x,int y,int z){
    cnt++;
    b[cnt].to=y;
    b[cnt].wi=z;
    b[cnt].nex=f[x];
    f[x]=cnt;
}
queue<int>q;
int dis[maxn];
bool vis[maxn];
inline int bfs(){
    while(!q.empty())q.pop();
    q.push(S);
    memset(dis,-1,sizeof dis);
    dis[S]=0;
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=f[x];i;i=b[i].nex){
            int v=b[i].to;
            if(dis[v]<0&&b[i].wi){
                dis[v]=dis[x]+1;
                if(v==T)return 1;
                q.push(v);
            }
        }
    } 
    return 0;
}
inline int dfs(int x,int li){
    if(x==T||!li)return li;
    int used=li;
    vis[x]=1;
    for(int i=f[x];i;i=b[i].nex){
        int v=b[i].to;
        if(!vis[v]){
            if(dis[v]==dis[x]+1&&used&&b[i].wi){
                int re=dfs(v,min(b[i].wi,used));
                used-=re;
                b[i].wi-=re;
                b[i^1].wi+=re;
            }
        }
    }
    return li-used;
}
void dinic(){
    int ans=0;
    while(bfs()){
        memset(vis,0,sizeof vis);
        ans+=dfs(S,INT);
    }
    cout<<ans;
}
int main(){
    n=read();m=read();S=read();T=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read(),z=read();
        add(x,y,z);
        add(y,x,0);
    } 
    dinic();
    return 0;
}
网络流

真noip


【模板】最小费用最大流

技术分享
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring> 
const int maxn=100000+2333;
const int maxm=100000+99999;
const int INT=1e7;
using namespace std;
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<0||9<ch){ch=getchar();}
    while(0<=ch&&ch<=9){an=(an<<1)+(an<<3)+(ch^48);ch=getchar();}
    return an;
}
int f[maxn],S,T,n,m,cnt=1;
struct saber{
int wi,nex,to,fi;
}b[maxn<<2];
inline void add(int x,int y,int z,int fi){
    cnt++;
    b[cnt].to=y;
    b[cnt].wi=z;
    b[cnt].fi=fi;
    b[cnt].nex=f[x];
    f[x]=cnt;
}
deque<int>q;
int dis[maxn];
bool vis[maxn],in[maxn];
inline int bfs(){
    while(!q.empty())q.pop_front();
    q.push_back(S);
    for(int i=0;i<=n+2;i++)dis[i]=INT;
    memset(in,0,sizeof in);
    dis[S]=0;
    while(!q.empty()){
        int x=q.front();q.pop_front();in[x]=0;
        for(int i=f[x];i;i=b[i].nex){
            int v=b[i].to;
            if(dis[v]>dis[x]+b[i].fi&&b[i].wi){
                dis[v]=dis[x]+b[i].fi;
                if(!in[v]){
                in[v]=1;
                if(!q.empty()&&dis[v]<dis[q.front()])q.push_front(v);
                else q.push_back(v);
                } 
            }
        }
    }
    return dis[T]<INT;
}
inline int dfs(int x,int li){
    if(x==T||!li)return li;
    int used=li;
    vis[x]=1;
    for(int i=f[x];i;i=b[i].nex){
        int v=b[i].to;
        if(!vis[v]){
            if(dis[v]==dis[x]+b[i].fi&&used&&b[i].wi){
                int re=dfs(v,min(b[i].wi,used));
                used-=re;
                b[i].wi-=re;
                b[i^1].wi+=re;
            }
        }
    }
    return li-used;
}
void dinic(){
    int ans=0;
    int fe=0;
    while(bfs()){
        memset(vis,0,sizeof vis);
        int v=dfs(S,INT);
        ans+=v;
        fe+=dis[T]*v;
    }
    cout<<ans<<" "<<fe;
}
int main(){
    n=read();m=read();S=read();T=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read(),z=read(),fi=read();
        add(x,y,z,fi);
        add(y,x,0,-fi);
    }
    dinic();
    return 0;
}
费用流

在网络流上加最短路


【模板】负环

技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=200000+2333; 
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(0<=ch&&ch<=9){an=an*10+ch-0;ch=getchar();}
    return an*f;
}
struct saber{
int nex,wi,to;
}b[maxn<<1];
int f[maxn],dis[maxn],T,cnt,n,m,flag;
bool vis[maxn];
inline void add2(int x,int y,int z){
    cnt++;
    b[cnt].to=y;
    b[cnt].wi=z;
    b[cnt].nex=f[x];
    f[x]=cnt;
}
inline void add(int x,int y,int z){
    if(z>0)add2(x,y,z),add2(y,x,z);
    else add2(x,y,z);
}
inline void dfs(int x){
    if(vis[x]){flag=1;return ;}
    vis[x]=1;
    for(int i=f[x];i&&!flag;i=b[i].nex){
        int v=b[i].to;
        if(dis[v]>dis[x]+b[i].wi){
            dis[v]=dis[x]+b[i].wi;
            dfs(v);
        }
    }
    vis[x]=0;
}
int main(){
    T=read();
    ios::sync_with_stdio(0);
    while(T){T--;
        flag=0;
        cnt=0;
        memset(vis,0,sizeof vis);
        memset(dis,0,sizeof dis);
        memset(f,0,sizeof f);
        n=read();m=read();
        for(int i=1;i<=m;i++){
            int x=read(),y=read(),z=read();
            add(x,y,z);
        }
        for(int i=1;i<=n&&!flag;i++){
            dfs(i);
        }
        if(!flag)cout<<"N0\n";
        else cout<<"YE5\n";
    }
}
负环

dfs判负环


【模板】二分图匹配

技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const int maxn=3000;
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(0<=ch&&ch<=9){an=(an<<3)+(an<<1)+ch-0;ch=getchar();}
    return an*f;
}
int f[maxn<<1],ans,cnt,n,m,e;
struct saber{
int nex,to;
}b[5000000];
inline void add(int x,int y){
    cnt++;
    b[cnt].to=y;
    b[cnt].nex=f[x];
    f[x]=cnt;
}
int in[maxn<<1];
bool vis[maxn<<1];
inline int dfs(int x){
    for(int i=f[x];i;i=b[i].nex){
        int v=b[i].to;
        if(!in[v]){in[v]=x;return 1;}
    }
    for(int i=f[x];i;i=b[i].nex){
        int v=b[i].to;
        if(vis[v])continue;
        vis[v]=1;
        if(dfs(in[v])){in[v]=x;return 1;}
    }
    return 0;
}
int main(){
    n=read();m=read();e=read();
    for(int i=1;i<=e;i++){
    int x=read(),y=read();
        if(y>m);
        else add(x,n+10+y);
    }
    for(int i=1;i<=n;i++){
    memset(vis,0,sizeof vis);
    if(dfs(i))ans++;
    }
    cout<<ans;
}
匈牙利算法

莫名其妙<网络流跑不A(竟然不是T


【模板】缩点

技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#define ll long long
using namespace std;
const int maxn=1e4+233+17+9;
const int maxm=1e5+2333+17+9+4950;
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(0<=ch&&ch<=9){an=(an<<3)+(an<<1)+ch-0;ch=getchar();}
    return an*f;
}
int scc,f[maxn],ff[maxn],id;
int dag[maxn],dfn[maxn],low[maxn],wi[maxn];
int bel[maxn];
int dp[maxn],cnt,ans,n,m,ins[maxn];
bool vis[maxn],in[maxn];
struct saber{
int nex,to;
}b[maxm],bb[maxm];
stack<int>s;
inline void add(int x,int y){
    cnt++;
    b[cnt].to=y;
    b[cnt].nex=f[x];
    f[x]=cnt;
}
inline void add2(int x,int y){
    cnt++;
    ins[y]++;
    bb[cnt].to=y;
    bb[cnt].nex=ff[x];
    ff[x]=cnt;
}
inline void dfs(int x){
    id++;
    dfn[x]=low[x]=id;
    in[x]=vis[x]=1;
    s.push(x);
    for(int i=f[x];i;i=b[i].nex){
        int v=b[i].to;
        if(!vis[v]){
            dfs(v);
            low[x]=min(low[x],low[v]);
        }
        else if(in[v])low[x]=min(low[x],dfn[v]);
    }
    if(dfn[x]==low[x]){
        int z=22333;scc++;
        while(z!=x){
            z=s.top();
            bel[z]=scc;
            dag[scc]+=wi[z];
            in[z]=0;
            s.pop();
        }
    }
}
queue<int>q;
inline void rebuild(){
    cnt=1;
    for(int i=1;i<=n;i++){
        for(int j=f[i];j;j=b[j].nex){
            int v=b[j].to;
            if(bel[i]!=bel[v])add2(bel[i],bel[v]);
        }
    }
}
inline void top_sort(){
    int flag,l=1;
    while(l<=n){
    memset(vis,0,sizeof vis);
    memset(dp,0,sizeof dp);
    while(l<=n){
    if(!ins[l]){q.push(l);flag=l;break;}
    else l++;
    }
    dp[flag]=dag[flag];
    while(!q.empty()){
        int x=q.front();q.pop();vis[x]=0;
        for(int i=ff[x];i;i=bb[i].nex){
            int v=bb[i].to;
            if(dp[v]<dp[x]+dag[v]){
            dp[v]=dp[x]+dag[v];
            if(!vis[v]){
                q.push(v);
                vis[v]=1;
                    }
                    }
            }
        ans=max(ans,dp[x]);
        }
        l=l+1;
        }
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)wi[i]=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        add(x,y);
    }
    for(int i=1;i<=n;i++)
    if(!vis[i])dfs(i);
    rebuild();
    top_sort();
    cout<<ans;
    return 0;    
}
dp

不要跑最短路>>


 

【模板】割点(割顶)

技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#define ll long long
using namespace std;
const int maxn=100000+2333+17+9+4950;
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(0<=ch&&ch<=9){an=(an<<3)+(an<<1)+ch-0;ch=getchar();}
    return an*f;
}
int f[maxn],n,m,cnt=1,id;
bool cut[maxn],vis[maxn];
int dfn[maxn],low[maxn],ans;
struct saber{
int nex,to;
}b[maxn<<1];
inline void add(int x,int y){
    cnt++;
    b[cnt].to=y;
    b[cnt].nex=f[x];
    f[x]=cnt;
}
inline int dfs(int x,int fa){
    int sum=0;bool cu=0;
    id++;
    dfn[x]=low[x]=id;vis[x]=1;
    for(int i=f[x];i;i=b[i].nex){
        int v=b[i].to;
        if(v==fa)continue;
        if(!vis[v]){
            sum++;
            dfs(v,x);
            low[x]=min(low[x],low[v]);
            if(low[v]>=dfn[x])cu=1;
        }
        else low[x]=min(low[x],dfn[v]);
    }
    if(!fa){if(sum>1)ans++,cut[x]=1;}
    else if(cu)ans++,cut[x]=1;
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        add(x,y);add(y,x);
    }
    for(int i=1;i<=n;i++)
    if(!vis[i])dfs(i,0);
    cout<<ans<<"\n";
    for(int i=1;i<=n;i++)if(cut[i])cout<<i<<" ";
    return 0;
}
割点

贪心,先找根,然后判下面是否割


【模板】卢卡斯定理

技术分享
#include<iostream>
#include<cstdlib>
#define ll long long 
using namespace std;
ll T,p;
ll f[500000];
ll ks(ll y,ll k){
    ll s=y,ans=1;
    while(k){
        if(k&1)ans=ans*s%p;
        s=s*s%p;
        k>>=1;
    }
    return ans%p;
}
ll C(ll n,ll m){
    if(m>n)return 0;
    return f[n]*ks(f[m]*f[n-m],p-2)%p;
}
ll Luc(ll n,ll m){
    if(!m)return 1;
    return (Luc(n/p,m/p)*C(n%p,m%p))%p;
}
int main(){
    cin>>T;
    while(T){
    ll n,m;
    T--;
    cin>>n>>m>>p;
    f[0]=1;
    for(int i=1;i<=p;i++)f[i]=f[i-1]*i%p;
    cout<<Luc(n+m,m)<<endl;}
    return 0;
}
组合数

数论


【模板】ST表

技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=100000+999;
int read(){
    int f=1,an=0;
    char ch=getchar();
    while(!(0<=ch&&ch<=9)){if(ch==-)f=-f;ch=getchar();}
    while(0<=ch&&ch<=9){an=an*10+(ch-0);ch=getchar();}
    return an*f;
}
int x,y,n,m;
struct saber{
int l,r,M;
}tr[maxn*4+999];
int a[maxn];
void build(int k,int l,int r){
    int mid=(l+r)>>1;
    tr[k].l=l;tr[k].r=r;
    if(l==r){tr[k].M=a[l];return;}
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    tr[k].M=max(tr[k<<1].M,tr[k<<1|1].M);
}
int ask(int k,int i,int j){
    int l=tr[k].l,r=tr[k].r;
    if(l==i&&j==r){
        return tr[k].M;}
    int mid=(l+r)>>1;
    if(j<=mid){return ask(k<<1,i,j);}
    else if(i>mid){return ask(k<<1|1,i,j);}
    else {return max(ask(k<<1,i,mid),ask(k<<1|1,mid+1,j));}
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)a[i]=read();
    build(1,1,n);
    for(int i=1;i<=m;i++){
        x=read();y=read();
        printf("%d\n",ask(1,x,y));
    }
    return 0;
}
线段树
技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
const int maxn=1e5+2333;
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(0<=ch&&ch<=9){an=an*10+ch-0;ch=getchar();}
    return an*f;
}
int st[maxn][20],n,q;
int main(){
    ios::sync_with_stdio(0);
    n=read();q=read();
    for(int i=1;i<=n;i++)st[i][0]=read();
    for(int j=1;j<=20;j++)
    for(int i=1;i+(1<<j-1)-1<=n;i++)
    st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
    while(q){q--;
        int l=read(),r=read();
        int k=log2(r-l+1);
        cout<<max(st[l][k],st[r-(1<<k)+1][k])<<"\n";
    }
    return 0;
}
st

【模板】矩阵快速幂

技术分享
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
typedef long long ll;
using namespace std;

ll n,m,i,j,k;

struct Matrix{
    ll a[105][105];
    inline Matrix operator *(const Matrix &b)const
    {
        Matrix ret;
        for (ll i=1;i<=n;i++)
            for (ll j=1;j<=n;j++)
            {
                ret.a[i][j]=0;
                for (ll k=1;k<=n;k++)
                    ret.a[i][j]+=a[i][k]*b.a[k][j],ret.a[i][j]%=1000000007;
            }
        return ret;
    }
}a;

inline ll read()
{
    ll iep=1,ret=0;char ch=getchar();
    while (ch<0||ch>9){if (ch==-) iep=-1;ch=getchar();}
    while (ch>=0&&ch<=9){ret=ret*10+ch-0;ch=getchar();}
    return ret*iep;
}

Matrix ksm(Matrix a,ll x)
{
    Matrix ret,k;k=a;
    ret=a;x--;
    for (;x;x>>=1,k=k*k)
        if (x&1) ret=ret*k;
    return ret;
}

int main()
{
    n=read();k=read();
    for (i=1;i<=n;i++)
        for (j=1;j<=n;j++)
            a.a[i][j]=read();
    a=ksm(a,k);
    for (i=1;i<=n;i++)
    {
        for (j=1;j<n;j++) printf("%d ",a.a[i][j]);
        printf("%d\n",a.a[i][n]);
    }
}
QAQ

想当初不会啊

 

以上是关于noip2017酱油记前篇的主要内容,如果未能解决你的问题,请参考以下文章

游记noip2017酱油记

NOIP2017 酱油送命记

Noip2017酱油记(自我吐槽版)

HEOI2017 酱油记

GDKOI2018酱油记

SHTSC2017酱油记~~~