【NOIP2018】模板复习

线段树

note : 如果要区间赋值为0要注意mark不要用0作为无标记

/************************************************
*Author        :  lrj124
*Created Time  :  2018.11.05.16:31
*Mail          :  1584634848@qq.com
*Problem       :  seg
************************************************/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
int n,m;
struct seg {
    long long sum;
    int l,r,mark;
}tree[maxn<<2];
inline void pushup(int root) { tree[root].sum = tree[root<<1].sum+tree[root<<1|1].sum; }
inline void pushdown(int root) {
    if (tree[root].mark) {
        tree[root<<1].mark += tree[root].mark;
        tree[root<<1].sum += tree[root].mark*(tree[root<<1].r-tree[root<<1].l+1);
        tree[root<<1|1].mark += tree[root].mark;
        tree[root<<1|1].sum += tree[root].mark*(tree[root<<1|1].r-tree[root<<1|1].l+1);
        tree[root].mark = 0;
    }
}
inline void build(int l,int r,int root) {
    tree[root].l = l;
    tree[root].r = r;
    if (l == r) {
        scanf("%lld",&tree[root].sum);
        return;
    }
    int mid = l+r>>1;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);
    pushup(root);
}
inline void update(int l,int r,int ql,int qr,int root,long long x) {
    if (r < ql || l > qr) return;
    if (ql <= l && r <= qr) {
        tree[root].sum += x*(r-l+1);
        tree[root].mark += x;
        return;
    }
    pushdown(root);
    int mid = l+r>>1;
    update(l,mid,ql,qr,root<<1,x);
    update(mid+1,r,ql,qr,root<<1|1,x);
    pushup(root);
}
inline long long query(int l,int r,int ql,int qr,int root) {
    if (r < ql || l > qr) return 0;
    if (ql <= l && r <= qr) return tree[root].sum;
    pushdown(root);
    int mid = l+r>>1;
    return query(l,mid,ql,qr,root<<1)+query(mid+1,r,ql,qr,root<<1|1);
}
int main() {
    //freopen("seg.in","r",stdin);
    //freopen("seg.out","w",stdout);
    scanf("%d%d",&n,&m);
    build(1,n,1);
    while (m--) {
        int op,l,r;
        long long x;
        scanf("%d%d%d",&op,&l,&r);
        if (op == 1) {
            scanf("%lld",&x);
            update(1,n,l,r,1,x);
        } else printf("%lld\n",query(1,n,l,r,1));
    }
    //cerr << 1.0*clock()/CLOCKS_PER_SEC << endl;
    return 0;
}

树链剖分

note : 如果维护的是边权的话在update和query的最后一句num[u]改为num[u]+1

/************************************************
*Author        :  lrj124
*Created Time  :  2018.11.05.17:03
*Mail          :  1584634848@qq.com
*Problem       :  tcd
************************************************/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
int cnt,n,m,rt,p,val[maxn],dep[maxn],father[maxn],top[maxn],size[maxn],son[maxn],Map[maxn],num[maxn];
vector<int> edge[maxn];
inline void dfs1(int now,int fa) {
    dep[now] = dep[fa]+1;
    father[now] = fa;
    size[now] = 1;
    for (size_t i = 0;i < edge[now].size();i++)
        if (edge[now][i] ^ fa) {
            dfs1(edge[now][i],now);
            size[now] += size[edge[now][i]];
            if (size[edge[now][i]] > size[son[now]]) son[now] = edge[now][i];
        }
}
inline void dfs2(int now,int ntop) {
    num[now] = ++cnt;
    Map[num[now]] = now;
    top[now] = ntop;
    if (son[now]) dfs2(son[now],ntop);
    for (size_t i = 0;i < edge[now].size();i++)
        if (edge[now][i] ^ father[now] && edge[now][i] ^ son[now]) dfs2(edge[now][i],edge[now][i]);
}
struct seg { long long sum,l,r,mark; } tree[maxn<<2];
inline void pushup(int root) { tree[root].sum = tree[root<<1].sum+tree[root<<1|1].sum; }
inline void pushdown(int root) {
    if (tree[root].mark) {
        tree[root<<1].mark += tree[root].mark;
        tree[root<<1|1].mark += tree[root].mark;
        tree[root<<1].sum += tree[root].mark*(tree[root<<1].r-tree[root<<1].l+1);
        tree[root<<1|1].sum += tree[root].mark*(tree[root<<1|1].r-tree[root<<1|1].l+1);
        tree[root].mark = 0;
    }
}
inline void build(int l,int r,int root) {
    tree[root].l = l;
    tree[root].r = r;
    if (l == r) {
        tree[root].sum = val[Map[l]];
        return;
    }
    int mid = l+r>>1;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);
    pushup(root);
}
inline void update(int l,int r,int ql,int qr,int root,int x) {
    if (r < ql || l > qr) return;
    if (ql <= l && r <= qr) {
        tree[root].sum += x*(r-l+1);
        tree[root].mark += x;
        return;
    }
    pushdown(root);
    int mid = l+r>>1;
    update(l,mid,ql,qr,root<<1,x);
    update(mid+1,r,ql,qr,root<<1|1,x);
    pushup(root);
}
inline long long query(int l,int r,int ql,int qr,int root) {
    if (r < ql || l > qr) return 0;
    if (ql <= l && r <= qr) return tree[root].sum;
    int mid = l+r>>1;
    pushdown(root);
    return query(l,mid,ql,qr,root<<1)+query(mid+1,r,ql,qr,root<<1|1);
}
inline void updateroad(int u,int v,long long x) {
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]]) swap(u,v);
        update(1,n,num[top[u]],num[u],1,x);
        u = father[top[u]];
    }
    if (dep[u] > dep[v]) swap(u,v);
    update(1,n,num[u],num[v],1,x);
}
inline long long queryroad(int u,int v) {
    long long sum = 0;
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]]) swap(u,v);
        sum = (sum+query(1,n,num[top[u]],num[u],1))%p;
        u = father[top[u]];
    }
    if (dep[u] > dep[v]) swap(u,v);
    return (sum+query(1,n,num[u],num[v],1))%p;
}
int main() {
    //freopen("tcd.in","r",stdin);
    //freopen("tcd.out","w",stdout);
    scanf("%d%d%d%d",&n,&m,&rt,&p);
    for (int i = 1;i <= n;i++) scanf("%d",&val[i]);
    for (int i = 1,u,v;i < n;i++) {
        scanf("%d%d",&u,&v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    dfs1(rt,0);
    dfs2(rt,rt);
    build(1,n,1);
    while (m--) {
        int op,u,v;
        long long w;
        scanf("%d%d",&op,&u);
        if (op == 1) {
            scanf("%d%lld",&v,&w);
            updateroad(u,v,w);
        }
        if (op == 2) {
            scanf("%d",&v);
            printf("%lld\n",queryroad(u,v));
        }
        if (op == 3) {
            scanf("%lld",&w);
            update(1,n,num[u],num[u]+size[u]-1,1,w);
        }
        if (op == 4) printf("%lld\n",query(1,n,num[u],num[u]+size[u]-1,1)%p);
    }
    //cerr << 1.0*clock()/CLOCKS_PER_SEC << endl;
    return 0;
}

Splay

splay旋转过程(旋转 $x$ , $y$ 为 $x$ 的父亲, $z$ 为 $y$ 的父亲) : 

  1. 把 $x$ 旋转为 $z$ 的儿子, $x$ 的父亲更新为 $y$

  2. 把 $x$ 的儿子给 $y$ , $x$ 儿子的父亲更新为 $y$

  3. $y$ 变为 $x$ 的儿子, $y$ 的父亲更新为 $x$

  4. $pushup(y) \ , \ pushup(x)$ (先 $pushup(y)$ !)

......不想打了

二分图匹配

匈牙利:

note :

正确 :

match[edge[now][i]] = now;

错误 :

match[now] = edge[now][i];
/************************************************
*Author        :  lrj124
*Created Time  :  2018.11.06.19:07
*Mail          :  1584634848@qq.com
*Problem       :  hung
************************************************/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 10;
int n,m,e,match[maxn],ans;
vector<int> edge[maxn];
bool vis[maxn];
inline bool dfs(int now) {
    for (size_t i = 0;i < edge[now].size();i++)
        if (!vis[edge[now][i]]) {
            vis[edge[now][i]] = true;
            if (!match[edge[now][i]] || dfs(match[edge[now][i]])) {
                match[edge[now][i]] = now;
                return true;
            }
        }
    return false;
}
int main() {
    //freopen("hung.in","r",stdin);
    //freopen("hung.out","w",stdout);
    scanf("%d%d%d",&n,&m,&e);
    for (int i = 1,u,v;i <= e;i++) {
        scanf("%d%d",&u,&v);
        if (v > m) continue;
        edge[u].push_back(v);
    }
    for (int i = 1;i <= n;i++) {
        memset(vis,false,sizeof(vis));
        if (dfs(i)) ans++;
    }
    printf("%d",ans);
    //cerr << 1.0*clock()/CLOCKS_PER_SEC << endl;
    return 0;
}

Dinic: 

/************************************************
*Author        :  lrj124
*Created Time  :  2018.11.06.20:19
*Mail          :  1584634848@qq.com
*Problem       :  dinic
************************************************/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000000 + 10;
const int INF = 9999999;
int n,m,e,s,t,dep[maxn],first[maxn],edgecnt = -1;
struct edge { int to,next,w; } eg[maxn];
inline void addedge(int u,int v,int w) {
    eg[++edgecnt] = (edge){v,first[u],w},first[u] = edgecnt;
    eg[++edgecnt] = (edge){u,first[v],0},first[v] = edgecnt;
}
queue<int> Q;
inline int bfs() {
    memset(dep,0,sizeof(dep));
    Q.push(s);
    dep[s] = 1;
    while (!Q.empty()) {
        int now = Q.front(); Q.pop();
        for (int i = first[now];~i;i = eg[i].next)
            if (eg[i].w > 0 && !dep[eg[i].to]) {
                Q.push(eg[i].to);
                dep[eg[i].to] = dep[now]+1;
            }
    }
    return dep[t];
}
inline int dfs(int now,int flow) {
    int tmp = flow;
    if (now == t) return flow;
    for (int i = first[now];~i;i = eg[i].next)
        if (dep[eg[i].to] == dep[now]+1 && eg[i].w) {
            int f = dfs(eg[i].to,min(eg[i].w,tmp));
            if (f > 0) {
                eg[i].w -= f;
                eg[i^1].w += f;
                tmp -= f;
                if (!tmp) break;
            }
        }
    return flow-tmp;
}
inline int dinic() {
    int ans = 0;
    while (bfs()) ans += dfs(s,INF);
    return ans;
}
int main() {
    //freopen("dinic.in","r",stdin);
    //freopen("dinic.out","w",stdout);
    memset(first,-1,sizeof(first));
    scanf("%d%d%d",&n,&m,&e);
    for (int i = 1,u,v;i <= e;i++) {
        scanf("%d%d",&u,&v);
        if (v > m) continue;
        v += n;
        addedge(u,v,1);
    }
    s = n+m+1;
    t = n+m+2;
    for (int i = 1;i <= n;i++) addedge(s,i,1);
    for (int i = 1;i <= m;i++) addedge(i+n,t,1);
    printf("%d",dinic());
    //cerr << 1.0*clock()/CLOCKS_PER_SEC << endl;
    return 0;
}

网络最大流

note : 边的编号从0开始!

/************************************************
*Author        :  lrj124
*Created Time  :  2018.11.06.19:25
*Mail          :  1584634848@qq.com
*Problem       :  dinic
************************************************/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10000 + 10;
const int INF = 9999999;
int n,m,s,t,dep[maxn],first[maxn],edgecnt = -1;
struct edge { int to,next,w; } eg[maxn*20];
inline void addedge(int u,int v,int w) {
    eg[++edgecnt] = (edge){v,first[u],w},first[u] = edgecnt;
    eg[++edgecnt] = (edge){u,first[v],0},first[v] = edgecnt;
}
queue<int> Q;
inline int bfs() {
    memset(dep,0,sizeof(dep));
    Q.push(s);
    dep[s] = 1;
    while (!Q.empty()) {
        int now = Q.front(); Q.pop();
        for (int i = first[now];~i;i = eg[i].next)
            if (eg[i].w > 0 && !dep[eg[i].to]) {
                Q.push(eg[i].to);
                dep[eg[i].to] = dep[now]+1;
            }
    }
    return dep[t];
}
inline int dfs(int now,int flow) {
    int tmp = flow;
    if (now == t) return flow;
    for (int i = first[now];~i;i = eg[i].next)
        if (dep[eg[i].to] == dep[now]+1 && eg[i].w) {
            int f = dfs(eg[i].to,min(eg[i].w,tmp));
            if (f > 0) {
                eg[i].w -= f;
                eg[i^1].w += f;
                tmp -= f;
                if (!tmp) break;
            }
        }
    return flow-tmp;
}
inline int dinic() {
    int ans = 0;
    while (bfs()) ans += dfs(s,INF);
    return ans;
}
int main() {
    //freopen("dinic.in","r",stdin);
    //freopen("dinic.out","w",stdout);
    memset(first,-1,sizeof(first));
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for (int i = 1,u,v,w;i <= m;i++) {
        scanf("%d%d%d",&u,&v,&w);
        addedge(u,v,w);
    }
    printf("%d",dinic());
    //cerr << 1.0*clock()/CLOCKS_PER_SEC << endl;
    return 0;
}

扩展欧几里德

/************************************************
*Author        :  lrj124
*Created Time  :  2018.11.09.12:43
*Mail          :  1584634848@qq.com
*Problem       :  exgcd
************************************************/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll exgcd(ll a,ll b,ll& x,ll& y) {
	if (!b) {
		x = 1;
		y = 0;
		return a;
	}
	int tmp = exgcd(b,a%b,y,x);
	y -= (a/b)*x;
	return tmp;
}
int main() {
	//freopen("exgcd.in","r",stdin);
	//freopen("exgcd.out","w",stdout);
	ll a,b,x,y;
	scanf("%lld%lld",&a,&b);
	exgcd(a,b,x,y);
	printf("%lld",(x+b)%b);
	return 0;
}

有理数取余

如果p是质数可以用$\frac{a}{b} = a \times b^{p-2} \ mod \ p$

/************************************************
*Author        :  lrj124
*Created Time  :  2018.11.09.12:43
*Mail          :  1584634848@qq.com
*Problem       :  exgcd
************************************************/
#include <bits/stdc++.h>
using namespace std;
const int MOD = 19260817;
typedef long long ll;
inline void read(ll &x) {
    int p = 1;
    char ch;
    while ((ch = getchar()) > '9' || ch < '0') if (ch == '-') p = -1;
    x = ch-'0';
    while ((ch = getchar()) <= '9' && ch >= '0') x = (x*10+ch-'0')%MOD;
    x *= p;
}
inline ll exgcd(ll a,ll b,ll& x,ll& y) {
    if (!b) {
        x = 1;
        y = 0;
        return a;
    }
    int tmp = exgcd(b,a%b,y,x);
    y -= (a/b)*x;
    return tmp;
}
int main() {
    //freopen("exgcd.in","r",stdin);
    //freopen("exgcd.out","w",stdout);
    ll a = 0,b = 0,x,y;
    read(a),read(b);
    if (!b) {
        printf("Angry!");
        return 0;
    }
    exgcd(b,MOD,x,y);
    printf("%lld",(x+MOD)%MOD*a%MOD);
    return 0;
}

Dijkstra

单源最短路

/************************************************
*Author        :  lrj124
*Created Time  :  2018.11.09.08:22
*Mail          :  1584634848@qq.com
*Problem       :  dijksttra
************************************************/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
int n,m,s,first[maxn],edgecnt;
long long dis[maxn];
bool vis[maxn];
struct edge { int to,next,w; } eg[maxn*4];
inline void addedge(int u,int v,int w) {
    eg[++edgecnt] = (edge){v,first[u],w};
    first[u] = edgecnt;
}
priority_queue<pair<long long,int> > Q;
inline void Dijkstra() {
    for (int i = 1;i <= n;i++) dis[i] = 2147483647;
    Q.push(make_pair(0,s));
    dis[s] = 0;
    while (!Q.empty()) {
        int now = Q.top().second; Q.pop();
        if (vis[now]) continue;
        vis[now] = true;
        for (int i = first[now];~i;i = eg[i].next)
            if (dis[eg[i].to] > dis[now]+eg[i].w) {
                dis[eg[i].to] = dis[now]+eg[i].w;
                Q.push(make_pair(-dis[eg[i].to],eg[i].to));
            }
    }
}
int main() {
    //freopen("dijksttra.in","r",stdin);
    //freopen("dijksttra.out","w",stdout);
    memset(first,-1,sizeof(first));
    scanf("%d%d%d",&n,&m,&s);
    for (int i = 1,u,v,w;i <= m;i++) {
        scanf("%d%d%d",&u,&v,&w);
        addedge(u,v,w);
    }
    Dijkstra();
    for (int i = 1;i <= n;i++) printf("%lld ",dis[i]);
    return 0;
}

最短路计数

/************************************************
*Author        :  lrj124
*Created Time  :  2018.11.09.08:39
*Mail          :  1584634848@qq.com
*Problem       :  dijkstra
************************************************/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000000 + 10;
const int MOD = 100003;
int n,m,edgecnt,first[maxn];
long long dis[maxn],cnt[maxn];
bool vis[maxn];
struct edge { int to,next,w; } eg[maxn*4];
inline void addedge(int u,int v,int w) {
	eg[++edgecnt] = (edge){v,first[u],w}; first[u] = edgecnt;
	eg[++edgecnt] = (edge){u,first[v],w}; first[v] = edgecnt;
}
priority_queue<pair<int,int> > Q;
inline void Dijkstra(int s) {
	for (int i = 1;i <= n;i++) dis[i] = 2147483647;
	Q.push(make_pair(0,s));
	dis[s] = 0;
	cnt[s] = 1;
	while (!Q.empty()) {
		int now = Q.top().second; Q.pop();
		if (vis[now]) continue;
		vis[now] = true;
		for (int i = first[now];~i;i = eg[i].next)
			if (dis[eg[i].to] > dis[now]+eg[i].w) {
				dis[eg[i].to] = dis[now]+eg[i].w;
				cnt[eg[i].to] = cnt[now];
				Q.push(make_pair(-dis[eg[i].to],eg[i].to));
			}  else if (dis[eg[i].to] == dis[now]+eg[i].w) cnt[eg[i].to] = (cnt[eg[i].to]+cnt[now])%MOD;
	}
}
int main() {
	//freopen("dijkstra.in","r",stdin);
	//freopen("dijkstra.out","w",stdout);
	memset(first,-1,sizeof(first));
	scanf("%d%d",&n,&m);
	for (int i = 1,u,v;i <= m;i++) {
		scanf("%d%d",&u,&v);
		addedge(u,v,1);
	}
	Dijkstra(1);
	for (int i = 1;i <= n;i++) printf("%lld\n",cnt[i]);
	return 0;
}

LCA

倍增:

/************************************************
*Author        :  lrj124
*Created Time  :  2018.11.06.17:36
*Mail          :  1584634848@qq.com
*Problem       :  lca
************************************************/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 500000 + 10;
int n,m,s,dep[maxn],father[maxn][30];
vector<int> edge[maxn];
inline void dfs(int now,int fa) {
    dep[now] = dep[fa]+1;
    father[now][0] = fa;
    for (size_t i = 0;i < edge[now].size();i++)
        if (edge[now][i] ^ fa) dfs(edge[now][i],now);
}
inline void init() {
    for (int j = 1;j <= 20;j++)
        for (int i = 1;i <= n;i++)
            father[i][j] = father[father[i][j-1]][j-1];
}
inline int lca(int u,int v) {
    if (dep[u] < dep[v]) swap(u,v);
    for (int i = 20;i >= 0;i--)
        if (dep[father[u][i]] >= dep[v]) u = father[u][i];
    if (u == v) return u;
    for (int i = 20;i >= 0;i--)
        if (father[u][i] ^ father[v][i]) {
            u = father[u][i];
            v = father[v][i];
        }
    return father[u][0];
}
int main() {
    scanf("%d%d%d",&n,&m,&s);
    for (int i = 1,u,v;i < n;i++) {
        scanf("%d%d",&u,&v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    dfs(s,0);
    init();
    for (int u,v;m--;) {
        scanf("%d%d",&u,&v);
        printf("%d\n",lca(u,v));
    }
    //cerr << 1.0*clock()/CLOCKS_PER_SEC << endl;
    return 0;
}

重链剖分:

/************************************************
*Author        :  lrj124
*Created Time  :  2018.11.06.18:02
*Mail          :  1584634848@qq.com
*Problem       :  lca
************************************************/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 500000 + 10;
int n,m,s,father[maxn],dep[maxn],top[maxn],size[maxn],son[maxn];
vector<int> edge[maxn];
inline void dfs1(int now,int fa) {
    dep[now] = dep[fa]+1;
    father[now] = fa;
    size[now] = 1;
    for (size_t i = 0;i < edge[now].size();i++)
        if (edge[now][i] ^ fa) {
            dfs1(edge[now][i],now);
            size[now] += size[edge[now][i]];
            if (size[edge[now][i]] > size[son[now]]) son[now] = edge[now][i];
        }
}
inline void dfs2(int now,int ntop) {
    top[now] = ntop;
    if (son[now]) dfs2(son[now],ntop);
    for (size_t i = 0;i < edge[now].size();i++)
        if (edge[now][i] ^ father[now] && edge[now][i] ^ son[now]) dfs2(edge[now][i],edge[now][i]);
}
inline int lca(int u,int v) {
    while (top[u] ^ top[v]) {
        if (dep[top[u]] < dep[top[v]]) swap(u,v);
        u = father[top[u]];
    }
    if (dep[u] > dep[v]) swap(u,v);
    return u;
}
int main() {
    //freopen("lca.in","r",stdin);
    //freopen("lca.out","w",stdout);
    scanf("%d%d%d",&n,&m,&s);
    for (int i = 1,u,v;i < n;i++) {
        scanf("%d%d",&u,&v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    dfs1(s,0);
    dfs2(s,s);
    for (int u,v;m--;) {
        scanf("%d%d",&u,&v);
        printf("%d\n",lca(u,v));
    }
    //cerr << 1.0*clock()/CLOCKS_PER_SEC << endl;
    return 0;
}
posted @ 2018-11-06 17:28 lrj124 阅读(...) 评论(...) 编辑 收藏