[洛谷模板大赛]题解 模板整理QAQ

题目地址:NOIP RP++

题目描述不用说,都是交模板就能AC的,昨晚就A了4个题因为时间不太够了……
最近也想整理模板,看到这么个模板大赛自然是把持不住辣~
除了T2平衡树不会做之外其他的都可以,T5好像是递归版Spfa,现学了一下,其实思想都一样,不用学,其他的没什么了,看模板~
T1:线段树:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#define lson p<<1
#define rson p<<1|1
using namespace std;
typedef long long LL;
const int SIZE = 500010;
struct Tree{
    int l,r;
    LL sum,add;
}tree[SIZE<<2];
void build(int p,int l,int r)
{
    tree[p].l = l,tree[p].r = r;
    if(l == r)  return ;
    int mid = (l + r) >> 1;
    build(lson,l,mid);
    build(rson,mid+1,r);
}

inline void RD(int &x)
{
    x = 0;  char c; c = getchar();
    bool flag = 0;
    if(c == '-')    flag = 1;
    while(c < '0' || c > '9')
    {
        if(c == '-')    flag = 1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + c - '0',c = getchar();
    if(flag)    x = -x;
}

void spread(int p)
{
    if(tree[p].add)
    {
        tree[lson].sum += (LL)(tree[lson].r - tree[lson].l + 1) * tree[p].add;
        tree[rson].sum += (LL)(tree[rson].r - tree[rson].l + 1) * tree[p].add;
        tree[lson].add += tree[p].add;
        tree[rson].add += tree[p].add;
        tree[p].add = 0;
    }
}
void change(int p,int l,int r,int x)
{
    if(l <= tree[p].l && tree[p].r <= r)
    {
        tree[p].sum += (LL)x * (tree[p].r - tree[p].l + 1);
        tree[p].add += (LL)x;
        return ;
    }
    spread(p);
    int mid = (tree[p].l + tree[p].r) >> 1;
    if(l <= mid)    change(lson,l,r,x);
    if(mid < r)     change(rson,l,r,x);
    tree[p].sum = tree[lson].sum + tree[rson].sum;
}
LL ask(int p,int l,int r)
{
    if(l <= tree[p].l && tree[p].r <= r)    return tree[p].sum;
    spread(p);
    LL ans = 0;
    int mid = (tree[p].l + tree[p].r) >> 1;
    if(l <= mid)    ans += ask(lson,l,r);
    if(mid < r)     ans += ask(rson,l,r);
    return ans;
}
int n,m,q,l,r;
int x;
int main()
{
    RD(n);
    RD(m);
    build(1,1,n);
    while(m--)
    {
        RD(q);
        if(q == 2)
        {
            RD(l);
            RD(r);
            RD(x);
            change(1,l,r,x);
        }
        if(q == 1)
        {
            RD(l);
            RD(r);
            printf("%lld\n",ask(1,l,r));
        }
    }
    return 0;
}

T2:平衡树(听说线段树能做我也没仔细看……)
T3:堆
需要注意一下,把删除操作替换掉,就是每次要删除时直接标记那个数,等到查询那个数的时候再删除那个数,这样正确性仍然是能保证的~

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
using namespace std;
typedef long long LL;
map <int,bool> vis;

inline void RD(int &x)
{
    x = 0;  char c; c = getchar();
    bool flag = 0;
    if(c == '-')    flag = 1;
    while(c < '0' || c > '9')
    {
        if(c == '-')    flag = 1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + c - '0',c = getchar();
    if(flag)    x = -x;
}

priority_queue <int> q;
int n,a;
int main()
{
    RD(n);
    while(n--)
    {
        RD(a);
        if(a > 0)   q.push(a);
        else if(a == 0)
        {
            while(vis[q.top()]) q.pop();
            printf("%d\n",q.top());
        }
        else if(a < 0)  vis[-a] = 1;
    }
    return 0;
}

T4:二分图的最大匹配

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
typedef long long LL;
const int SIZE = 500010;
struct Edge{int to;}edges[SIZE];
int head[SIZE],next[SIZE],tot;
void build(int f,int t)
{
    edges[++tot].to = t;
    next[tot] = head[f];
    head[f] = tot;
}
inline void RD(int &x)
{
    x = 0;  char c; c = getchar();
    bool flag = 0;
    if(c == '-')    flag = 1;
    while(c < '0' || c > '9')   {if(c == '-')   {flag = 1;} c = getchar();}
    while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + c - '0',c = getchar();
}
bool vis[SIZE];
int connect[SIZE << 1];
bool dfs(int u)
{
    for(int i = head[u];i;i = next[i])
    {
        int v = edges[i].to;
        if(!vis[v])
        {
            vis[v] = 1;
            if(!connect[v] || dfs(connect[v]))
            {
                connect[v] = u;
                return true;
            }
        }
    }
    return false;
}
int n,m,k,a,b;
int main()
{
    RD(n),RD(m),RD(k);
    int mx = max(n,m);
    while(k --)
    {
        RD(a),RD(b);
        build(a,b+mx);
    }
    int cnt = 0;
    for(int i = 1;i <= n;i ++)
    {
        memset(vis,0,sizeof(vis));
        if(dfs(i))  cnt ++;
    }
    printf("%d\n",cnt);
    return 0;
}

T5:最短路
注意开long long ,以及把变量开在外面这个细节~

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
using namespace std;
typedef long long LL;
const int SIZE = 200010;
const LL INF = 2147483647233LL;
struct Edge{int to;LL dist;}edges[SIZE];
int head[SIZE],next[SIZE],tot;
void build(int f,int t,LL d)
{
    edges[++tot].to = t;
    edges[tot].dist = d;
    next[tot] = head[f];
    head[f] = tot;
}
deque <int> q;
LL dist[SIZE];
bool vis[SIZE];
int n,m,s,t;
void spfa()
{
    for(int i = 1;i <= n;i ++)  dist[i] = INF;
    q.push_back(s);
    vis[s] = 1;
    dist[s] = 0;
    while(!q.empty())
    {
        int f = q.front();
        q.pop_front();
        vis[f] = 0;
        for(int i = head[f];i;i = next[i])
        {
            int v = edges[i].to;
            if(dist[v] > dist[f] + edges[i].dist)
            {
                dist[v] = dist[f] + edges[i].dist;
                if(!vis[v])
                {
                    vis[v] = 1;
                    if(!q.empty() && dist[v] < dist[q.front()]) q.push_front(v);
                    else    q.push_back(v);
                }
            }
        }
    }
}
int a,b;
LL c;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= m;i ++)
    {
        scanf("%d %d %lld",&a,&b,&c);
//      cout<<a<<" "<<b<<" "<<c<<endl;
        build(a,b,c);
    }
    s = 1,t = n;
    spfa();
    if(dist[t] == INF)  puts("-1");
    else printf("%lld\n",dist[t]);
    return 0;
}

T6:dfs版的spfa判断负环

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
using namespace std;
typedef long long LL;
typedef double DB;
const int SIZE = 500010;
struct Edge{int to,dist;}edges[SIZE];
int head[SIZE],next[SIZE],tot;
void build(int f,int t,int d)
{
    edges[++tot].to = t;
    edges[tot].dist = d;
    next[tot] = head[f];
    head[f] = tot;
}
int n,m,a,b,c;
bool vis[SIZE];
int dist[SIZE];
bool flag = 0;
void spfa(int u)
{
    if(flag)    return ;
    for(int i = head[u];i;i = next[i])
    {
        int v = edges[i].to;
        if(dist[v] > dist[u] + edges[i].dist)
        {
            if(vis[v])  flag = 1;
            dist[v] = dist[u] + edges[i].dist;
            if(!vis[v])
            {
                vis[v] = 1;
                spfa(v);
                vis[v] = 0;
            }
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        tot = 0;
        memset(head,0,sizeof(head));
        memset(edges,0,sizeof(edges));
        memset(next,0,sizeof(next));
        scanf("%d%d",&n,&m);
        for(int i = 1;i <= m;i ++)
        {
            scanf("%d%d%d",&a,&b,&c);
            build(a,b,c);
            if(c >= 0)  build(b,a,c);
        }
        flag = 0;
        memset(dist,64,sizeof(dist));
        for(int i = 1;i <= n;i ++)
        {
            if(!vis[i])
            {
                spfa(i);
                if(flag)    {puts("YE5");break;}
            }
        }
        if(!flag)   puts("N0");
    }
    return 0;
}

T7:tarjian求割点

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
using namespace std;
typedef long long LL;
typedef double DB;
const int SIZE = 200010;
int n,m;
struct Edge{int to;}edges[SIZE];
int head[SIZE],next[SIZE],tot;
void build(int f,int t)
{
    edges[++tot].to = t;
    next[tot] = head[f];
    head[f] = tot;
}
int dfs_clock,low[SIZE],pre[SIZE];
bool iscut[SIZE];
bool dfs(int u,int fa)
{
    low[u] = pre[u] = ++dfs_clock;
    int child = 0;
    for(int i = head[u];i;i = next[i])
    {
        int v = edges[i].to;
        if(v == fa) continue;
        if(!pre[v])
        {
            child ++;
            dfs(v,u);
            low[u] = min(low[u],low[v]);
            if(pre[u] <= low[v])    iscut[u] = true;
        }
        else if(pre[v] < pre[u])
        {
            low[u] = min(low[u],pre[v]);
        }
    }
    if(child <= 1 && fa < 0)    iscut[u] = false;
}
int a,b;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= m;i ++)
    {
        scanf("%d%d",&a,&b);
        build(a,b);
        build(b,a);
    }
    for(int i = 1;i <= n;i ++) if(!pre[i])  dfs(i,-1);
    int cnt = 0;
    for(int i = 1;i <= n;i ++)  if(iscut[i])    cnt ++;
    printf("%d\n",cnt);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
思路1(洛谷题解) 设n维球体为α,其半径为r(注意,这是一个设而不求。),其球心X的坐标为(x_1,x_2,…,x_n )。∀A_1,A_2,…,A_(n+1)∈α,点A_i (1≤i≤n+1)坐标为(a_((i,1) ),a_((i,2) ),…,a_((i,n) ) )。由n维球体的定义,得方程组: {█((a_((1,1) )-x_1 )^2+(a_((1,2) )-x_2 )^2+⋯+(a_((1,n) )-x_n )^2=r^2@(a_((2,1) )-x_1 )^2+(a_((2,2) )-x_2 )^2+⋯+(a_((2,n) )-x_n )^2=r^2@⋮@(a_((n+1,1) )-x_1 )^2+(a_((n+1,2) )-x_2 )^2+⋯+(a_((n+1,n) )-x_n )^2=r^2 )┤. 从上往下,将第1个方程与第2个方程相减,将第2个方程与第3个方程相减,……,将第n个方程与第(n+1)个方程相减,得: {█(∑_(i=1)^n▒2(a_((1,i) )-a_((2,i) ) ) x_i=∑_(i=1)^n▒(a_((1,i) )+a_((2,i) ) )(a_((1,i) )-a_((2,i) ) ) @∑_(i=1)^n▒2(a_((2,i) )-a_((3,i) ) ) x_i=∑_(i=1)^n▒(a_((2,i) )+a_((3,i) ) )(a_((2,i) )-a_((3,i) ) ) @⋮@∑_(i=1)^n▒2(a_((n,i) )-a_((n+1,i) ) ) x_i=∑_(i=1)^n▒(a_((n,i) )+a_((n+1,i) ) )(a_((n,i) )-a_((n,i) ) ) )┤. 这是一个线性方程组,其增广矩阵为[■(2(a_((1,1) )-a_((2,1) ) )&⋯&2(a_((1,n) )-a_((2,n) ) )&∑_(i=1)^n▒(a_((1,i) )+a_((2,i) ) )(a_((1,i) )-a_((2,i) ) ) @⋮&⋱&⋮&⋮@2(a_((n,1) )-a_((n+1,1) ) )&⋯&2(a_((n,n) )-a_((n+1,n) ) )&∑_(i=1)^n▒(a_((n,i) )+a_((n+1,i) ) )(a_((n,i) )-a_((n+1,i) ) ) )],可用列主元高斯消元法求得其解。 思路2 n(n∈N_+ )维空间中到两个互不重合的点的距离相等的点的集合叫做这两个点的垂直平分图形。 求n维空间中两点的垂直平分图形的方程的基本思路: 设点A坐标为(a_1,a_2,…,a_n ),点B的坐标为(b_1,b_2,…,b_n ),A≠B,它们的垂直平分图形为β。取∀X∈β,其坐标为(x_1,x_2,…,x_n )。 由垂直平分图形的意义,得: |AX|=|BX|⇔|AX|^2=|BX|^2⇔∑_(i=1)^n▒(a_i-x_i )^2 =∑_(i=1)^n▒(b_i-x_i )^2 ⇔(∑_(i=1)^n▒〖a_i〗^2 )-2(∑_(i=1)^n▒〖a_i x_i 〗)+(∑_(i=1)^n▒〖x_i〗^2 )=(∑_(i=1)^n▒〖b_i〗^2 )-2(∑_(i=1)^n▒〖b_i x_i 〗)+(∑_(i=1)^n▒〖x_i〗^2 )⇔∑_(i=1)^n▒〖2(a_i-b_i ) x_i 〗=∑_(i=1)^n▒(a_i+b_i )(a_i-b_i ) . 最后出来的这个等式就是垂直平分图形的方程。 回到题目中,对于∀A_1,A_2,…,A_(n+1)∈α,取A_1,A_2为一对,A_2,A_3为一对,……,A_n,A_(n+1)为一对代入垂直平分图形的方程中,惊奇地发现得到的线性方程组与思路1中相同,接下来的解法也相同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值