AtCoder Beginner Contest 294(D-G

D - Bank (atcoder.jp)

        (1)题目大意

                给你N个id,以及Q个询问,1表示用未被用到的最小的一个id,2表示x这个id现在被用到了,3表示再喊已经被喊的最小的那个人的id。

         (2)解题思路

                用两个set模拟即可。

         (3)代码实现

#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <unordered_map>
#include <deque>
#include <bitset>
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define vl vector<ll>
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) (x).begin(),(x).end()
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
void solve()
{
    int n,m;
    cin >> n >> m;
    set <int> st,has;
    rep(i,1,n) st.insert(i);
    rep(i,1,m) {
        int op,x;
        cin >> op;
        if(op == 1) {
            int v = *st.begin();
            st.erase(st.begin());
            has.insert(v);
        }
        else if(op == 2) {
            cin >> x;
            has.erase(x);
        }
        else {
            cout << *has.begin() << endl;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T = 1;
    // cin >> T;
    while(T --) solve();
    return 0;
}

E - 2xN Grid (atcoder.jp)

        (1)题目大意

                给你一个2*L的矩阵,第一行有N1个小段,每一段是一个数,第二行有N2个小段,每一段也是一个数,问你有多少对A[1][j] = A[2][j]

         (2)解题思路

                类似于区间合并的思想,使用双指针,若当上下指针区间元素一样,则算这个区间的交集是多少,然后根据上下指针的右边界的大小移动指针即可。

         (3)代码实现

#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <unordered_map>
#include <deque>
#include <bitset>
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define vl vector<ll>
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) (x).begin(),(x).end()
#define PLL pair<ll,ll>
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
struct Node {
    ll l,r;
    int v;
}a[N],b[N];
ll inter(ll l1,ll r1,ll l2,ll r2)
{
    return min(r1,r2) - max(l1,l2) + 1;
}
void solve()
{
    ll L,n,m;
    cin >> L >> n >> m;
    ll st = 1,x;
    int v;
    rep(i,1,n) {
        cin >> v >> x;
        a[i] = {st,st + x - 1,v};
        st += x;
    }
    st = 1;
    rep(i,1,m) {
        cin >> v >> x;
        b[i] = {st,st + x - 1,v};
        st += x;
    }
    int l1 = 1,l2 = 1;
    ll ans = 0;
    while(l1 <= n + 1 && l2 <= m + 1) {
        if(a[l1].v == b[l2].v) ans += inter(a[l1].l,a[l1].r,b[l2].l,b[l2].r);
        if(a[l1].r >= b[l2].r) l2 ++;
        else l1 ++;
    }
    cout << ans << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T = 1;
    // cin >> T;
    while(T --) solve();
    return 0;
}

F - Sugar Water 2 (atcoder.jp)

        (1)题目大意

                两个人分别由N个瓶子和M个瓶子的糖水,设第一个人第i个瓶子由Ai克糖和Bi克水,第二个人第j个瓶子由Cj克糖和Dj克水,分别从两个人中取出一个瓶子,问你第k大糖分率是多少?

         (2)解题思路

                考虑k过大,因此考虑二分答案V

                式子可以写为\frac{xi + xj}{xi + yi + xj + yj} > V,若满足这个式子有大于V的个数有K个,那么此答案符合要求,把除法变乘法xi + xj > V(xi + yi + xj + yj),把i放一边j放一边变为(1-V)xi-Vyi>(V-1)xj+Vyj,把AB数组处理成左边式子,把CD数组处理成右边式子,排个序双指针扫一下看有多少个满足条件即可。

         (3)代码实现

#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <unordered_map>
#include <deque>
#include <bitset>
#include <iomanip>
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define vl vector<ll>
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) (x).begin(),(x).end()
using namespace std;
using ll = long long;
const double eps = 1e-14;
const int N = 2e5 + 10;
PII a[N],b[N];
long double A[N],B[N];
ll n,m,k;
bool check(long double V)
{
    rep(i,1,n) A[i] = (1 - V) * a[i].fi - V * a[i].se;
    rep(i,1,m) B[i] = (V - 1) * b[i].fi + V * b[i].se;
    sort(A + 1,A + 1 + n);
    sort(B + 1,B + 1 + m);
    ll cnt = 0,cur = 1;
    rep(i,1,n) {
        while(cur <= m && B[cur] <= A[i]) cur ++;
        cnt += cur - 1;
    }
    return cnt >= k;
}
void solve()
{
    cin >> n >> m >> k;
    cout << fixed << setprecision(15);
    rep(i,1,n) cin >> a[i].fi >> a[i].se;
    rep(i,1,m) cin >> b[i].fi >> b[i].se;
    long double l = 0,r = 1;
    while(r - l >= eps) {
        long double mid = (l + r) / 2;
        if(check(mid)) l = mid + eps;
        else r = mid - eps;
    }
    cout << l * 100 << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T = 1;
    // cin >> T;
    while(T --) solve();
    return 0;
}

G - Distance Queries on a Tree (atcoder.jp)

        (1)题目大意

                给你一颗树有N个节点,有两种操作,第一种操作是把第i条边的权值修改为w,第二个操作是询问u到v的路径和。

         (2)解题思路

                预处理出dfs序,因为树上操作不好直接修改,因此转换成区间问题,又因为是边权和,我们可以按照dfs序把边权转换为点权处理,按照拆点的思路把树上每一个点分成入点和出点,若修改了第i条边的权值,相当于修改了第i条边的入点的和,然后在这个出点+1的位置减去修改的即可,因此可以考虑树状数组进行单点修改和区间查询。

                注意查询的时候我们是qry[1,in[u]] + qry[1,in[v]] - 2 *qry[1,lca(in[u],in[v]));查询的时候是直接查询第u节点之前的和和节点之前的和然后减去他们2倍lca的和,因为他们lca之前的全部都重复了,比如。

                

        查询4和5的和,要减去2倍2之前的和。

        (3)代码实现

#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <unordered_map>
#include <deque>
#include <bitset>
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define vl vector<ll>
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) (x).begin(),(x).end()
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
int siz[N],in[N],out[N],son[N],fa[N],top[N],dep[N],pid[N],tim;
int he[N];
struct Edge {
    int x,y;
    int v;
}e[N];
vector <PII> G[N];
void dfs1(int u,int f)
{
    siz[u] = 1;
    in[u] = ++ tim;
    dep[u] = dep[f] + 1;
    fa[u] = f;
    for(auto x : G[u]) {
        if(x.fi == f) continue;
        dfs1(x.fi,u);
        pid[x.se] = x.fi;
        siz[u] += siz[x.fi];
        if(siz[x.fi] > siz[son[u]]) son[u] = x.fi;
    }
    out[u] = ++ tim;
}
void dfs2(int u,int f)
{
    top[u] = f;
    if(son[u]) dfs2(son[u],f);
    for(auto x : G[u]) {
        if(x.fi == fa[u] || x.fi == son[u]) continue;
        dfs2(x.fi,x.fi);
    }
}
int getLCA(int x,int y)
{
    while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]]) swap(x,y);
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x,y);
    return x;
}
struct Fenwick{
    ll tr[(N << 2) + 10];
    int n;
    Fenwick(int n = 0) {
        init(n);
    }
    void init(int n) {
        this->n = n;
        for(int i = 1;i <= n;++ i) {
            tr[i] = 0;
        }
    }
    int lowbit(int x) {
        return x & -x;
    }
    void add(int x,int v) {
        while(x <= n) {
            tr[x] += v;
            x += lowbit(x);
        }
    }
    ll qry(int x) {
        ll res = 0;
        while(x >= 1) {
            res += tr[x];
            x -= lowbit(x);
        }
        return res;
    }
};
void solve()
{
    int n,u,v;
    cin >> n;
    rep(i,1,n - 1) {
        int x,y,w;
        cin >> x >> y >> w;
        G[x].pb({y,i});G[y].pb({x,i});
        e[i] = {x,y,w};
    }
    dfs1(1,0);
    dfs2(1,0);
    Fenwick fen(n * 2);
    rep(i,1,n - 1) {
        int rp = pid[i];
        fen.add(in[rp],e[i].v);
        fen.add(out[rp] + 1,-e[i].v);
    }
    int q;
    cin >> q;
    while(q --) {
        int op,x,y;
        cin >> op >> x >> y;
        if(op == 1) {
            int rp = pid[x];
            fen.add(in[rp],y - e[x].v);
            fen.add(out[rp] + 1,e[x].v - y);
            e[x].v = y;
        }
        else {
            //询问x,y
            int pf = getLCA(x,y);
            cout << fen.qry(in[x]) + fen.qry(in[y]) - 2 * fen.qry(in[pf]) << endl;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T = 1;
    // cin >> T;
    while(T --) solve();
    return 0;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值