西南科技大学第十三届程序设计竞赛赛后总结

  这次的校赛没有能延续之前的传统体验到封榜后过题的快乐…… ——是有原因的

117分钟的时候,我们就已经过了7道题了,那之后我们就是在盲目目的地寻找着下一道可以做的题了,或许这就是没人带榜的尴尬所在了吧,然后我们就开始分题,我拿了B、H题(因为看上去像是数据结构),然后gyf去看了G,zxd开了K,因为那是道莫比乌斯问题,然后我们就开始各自开了,gyf先有了思路,跟我说了一番之后,觉得利用单调栈维护的分块可以去搞G,然后我们就先开了G,利用一个O(N*sqrt(N))的分块去写,写完之后再去看了下在跳入不同的块的时候一些小bug,然后过了我们手动的测试样例,交……T3,于是乎就大致知道,还是被卡了,这个方法不行,打印出来好好想想再做吧。

  然后我上手去敲B,B题就是一个求树的中心然后再从树的中心出发,选取(K-1)个点的求联通块出发达到的最远距离最小的这样一个问题,代码量有点大,然后我又没有听队友的话去敲树的直径的模版,而是想更快的求出树的中心,然后自己想了个树链剖分的两个dfs()的做法,这也是自己给自己埋坑了,封榜前20分钟的时候开始敲这道题,大致在封榜后20分钟不到的时候就敲完了这道题,然后就是去想办法debug,从后往前的看,发现优先队列那块并没有写错,然后再去找,发现树的中心没有求对,然后我根据我的思路不断的去debug,这时候,发现在往下走的时候,可能不是已经求得完全的最远距离值,中心点找错了,这时候,赛场那头,有个跟我们一样过了7题的队伍过了第8个题…… 开始有些些焦虑了吧,需要静下来好好想想,喝了杯水,抓紧时间去厕所洗了个脸,回来继续debug。时间就这样一分一秒的流逝,逐渐的发现我这样的去求树的中心远没有先求树的直径再求树的中心来的方便,还剩10分钟…… 尽力改回来吧,但是或许自己也知道最后是无力回天了。

  一意孤行成了最后没能过第八题的最大的因果,这时候其实应该跟队友有更多的交流,是这次的教训,赛后花了大概两个小时的时间去敲了B、G两道题,很快的就写了出来,而求G还要比标程快了一个logN的倍数。

  这次的院赛是一个很好的经验教训,我们各自都从这次的比赛中吸取到了自己的教训,也有了自己的收获吧,去更多的相信队友,去在更加合适的时机去做更加正确的敲手,在发现bug以及找出自己算法的优劣势上还需要更多的经验教训,总之,下个月的校赛,加油!


B题-小Z的糖果店

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define esp 1e-6
#define INF 0x3f3f3f3f3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, K, head[maxN], cnt;
struct Eddge
{
    int nex, to;
    ll len, all;
    Eddge(int a=-1, int b=0, ll c=0):nex(a), to(b), len(c) {}
}edge[maxN<<1];
inline void addEddge(int u, int v, ll w)
{
    edge[cnt] = Eddge(head[u], v, w);
    head[u] = cnt++;
}
int A, B;
ll maxx;
inline void dfs_B(int u, int fa, ll val)
{
    if(val > maxx) { maxx = val; B = u; }
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to; ll c = edge[i].len;
        if(v == fa) continue;
        dfs_B(v, u, val + c);
    }
}
int fa[maxN];
ll to_fa_dis[maxN];
inline void dfs_A(int u, int up, ll val)
{
    if(val > maxx) { maxx = val; A = u; }
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to; ll c = edge[i].len;
        if(v == up) continue;
        fa[v] = u;  to_fa_dis[v] = c;
        dfs_A(v, u, val + c);
    }
}
int mid;    ll minn;
inline void dfs_mid(int u, ll val)
{
    ll QWQ = max(val, maxx - val);
    if(QWQ < minn) { minn = QWQ; mid = u; }
    if(fa[u] == -1) return;
    dfs_mid(fa[u], val + to_fa_dis[u]);
}
ll dfs_sum_edge(int u, int rt)
{
    ll ans = 0;
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == rt) continue;
        ll tmp = dfs_sum_edge(v, u) + edge[i].len;
        ans = max(ans, tmp);
        edge[i].all = tmp;
    }
    return ans;
}
struct node
{
    int u;
    ll len;
    node(int a=0, ll b=0, ll c=0):u(a),len(b) {}
    friend bool operator < (node e1, node e2) { return e1.len < e2.len; }
};
priority_queue<node> Q;
bool inque[maxN];
inline void init()
{
    cnt = maxx = 0;
    for(int i=1; i<=N; i++) head[i] = fa[i] = -1;
    while(!Q.empty()) Q.pop();
    for(int i=1; i<=N; i++) inque[i] = false;
}
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &N, &K);
        if(N == 1) { printf("0\n"); continue; }
        init();
        for(int i=1, u ,v, w; i<N; i++)
        {
            scanf("%d%d%d", &u, &v, &w);
            addEddge(u, v, w);
            addEddge(v, u, w);
        }
        dfs_B(1, 0, 0); //此时已经知道了一端点B了,我们再去把A求出来
        maxx = 0;
        dfs_A(B, 0, 0);    //这时候把A点也找到了,树的长度为maxx了
        minn = INF;
        dfs_mid(A, 0);  //现在已经知道了中心了,只需要从中心出发去跑一遍它的直接方向上的边即可、不断拓展,存进优先队列
        dfs_sum_edge(mid, 0);   inque[mid] = true;  //必选的中心点。
        for(int i=head[mid], v; ~i; i=edge[i].nex)
        {
            v = edge[i].to;
            inque[v] = true;
            ll all = edge[i].all;
            Q.push(node(v, all));
        }
        for(int j=1; j<K; j++)
        {
            node temp = Q.top();    Q.pop();
            int u = temp.u;
            for(int i=head[u], v; ~i; i=edge[i].nex)
            {
                v = edge[i].to;
                if(inque[v]) continue;
                ll all = edge[i].all;
                Q.push(node(v, all));
                inque[v] = true;
            }
        }
        if(Q.empty()) printf("0\n");
        else
        {
            node temp = Q.top();
            printf("%lld\n", temp.len);
        }
    }
    return 0;
}

 


G题-小Z的糖果难题

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define esp 1e-6
#define INF 0x3f3f3f3f3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, Q, a[maxN], trie[maxN], ans[maxN];
struct Question
{
    int l, r, id;
    Question(int a=0, int b=0, int c=0):l(a), r(b), id(c) {}
}op[maxN];
bool cmp(Question e1, Question e2) { return e1.r > e2.r; }
inline void update(int i, int x)
{
    if(i == 0) return;
    while(i <= N)
    {
        trie[i] += x;
        i += lowbit(i);
    }
}
inline int query(int i)
{
    int ans = 0;
    while(i)
    {
        ans += trie[i];
        i -= lowbit(i);
    }
    return ans;
}
struct node
{
    int id, val;
    node(int a=0, int b=0):id(a), val(b) {}
};
stack<node> st;
int to[maxN];   //上一个比它大的节点的所在位置,为0就是没了
int behind[maxN];   //在下一个比它大的数之前,有几个数比它小或者等于
inline void init()
{
    for(int i=1; i<=N; i++) trie[i] = behind[i] = 0;
    while(!st.empty()) st.pop();
}
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &N, &Q);
        for(int i=1; i<=N; i++) scanf("%d", &a[i]);
        for(int i=1; i<=Q; i++) { scanf("%d%d", &op[i].l, &op[i].r); op[i].id = i; }
        sort(op + 1, op + Q + 1, cmp);
        init();
        to[1] = 0;
        st.push(node(1, a[1]));
        for(int i=2; i<=N; i++)
        {
            node tmp;
            to[i] = 0;
            while(!st.empty())
            {
                tmp = st.top();
                if(tmp.val >= a[i])
                {
                    to[i] = tmp.id;
                    //behind[tmp.id] = i - tmp.id;
                    behind[tmp.id]++;
                    break;
                }
                else st.pop();
            }
            st.push(node(i, a[i]));
        }
        int l = N, r = N;
        for(int q=1; q<=Q; q++)
        {
            while(r > op[q].r)
            {
                update(to[r], 1);
                r--;
            }
            while(l >= op[q].l)
            {
                update(l, -behind[l] + 1);
                l--;
            }
            ans[op[q].id] = query(op[q].r) - query(op[q].l - 1);
        }
        for(int i=1; i<=Q; i++) printf("%d\n", ans[i]);
    }
    return 0;
}
/*
1
9 7
5 7 6 2 6 6 2 7 8
6 9
5 7
9 9
1 4
5 9
4 7
2 9
*/

 


  题解与思路均放在超链接中了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Wuliwuliii

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

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

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

打赏作者

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

抵扣说明:

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

余额充值