P2783 有机化学之神偶尔会做作弊 [点双][树剖]

P2783 有机化学之神偶尔会做作弊

史上最水黑题

做法很暴力:tarjan算法求点双缩点,建新图,跑树剖或倍增,求LCA,通过深度算出答案即可。

点双的做法跟强连通分量的tarjan算法极其相似,唯一的一点不同就在于不能回到父节点。

要是回父节点的话那都有两个点大小的环咯

自己交上去45pts,原来是因为求LCA的时候下标弄错了。应该使用新图的下标。

代码:

/*************************************************************************
 @Author: Garen
 @Created Time : Thu 31 Jan 2019 05:21:10 PM CST
 @File Name: P2783.cpp
 @Description:
 ************************************************************************/
#include<bits/stdc++.h>
using std::cin;
using std::cout;
using std::endl;
#define ll long long
const int maxn = 50005, maxm = 100005;
struct Edges {
    int next, to;
} e[maxm << 1], e2[maxn << 1];
int head[maxn], tot;
int head2[maxn], tot2;
int n, m, q;
//
int dfn[maxn], low[maxn], dtot;
int stack[maxn << 1], stop;
bool vis[maxn];
int col[maxn], ctot;
//
int dep[maxn], fa[maxn], size[maxn], wson[maxn];
int top[maxn];
void link(int u, int v) {
    e[++tot] = (Edges){head[u], v};
    head[u] = tot;
}
void link2(int u, int v) {
    e2[++tot2] = (Edges){head2[u], v};
    head2[u] = tot2;
}
void tarjan(int u, int f) {
    dfn[u] = low[u] = ++dtot;
    stack[++stop] = u; vis[u] = true;
    for(int i = head[u]; i; i = e[i].next) {
        int v = e[i].to;
        if(v == f) continue;
        if(!dfn[v]) {
            tarjan(v, u); low[u] = std::min(low[u], low[v]);
        } else if(vis[v]) {
            low[u] = std::min(low[u], dfn[v]);
        }
    }
    if(dfn[u] == low[u]) {
        ctot++;
        int sb;
        do {
            sb = stack[stop--]; vis[sb] = false;
            col[sb] = ctot;
        } while(sb != u);
    }
}
void dfs1(int u, int f) {
    dep[u] = dep[f] + 1; fa[u] = f; size[u] = 1;
    for(int i = head2[u]; i; i = e2[i].next) {
        int v = e2[i].to;
        if(v == fa[u]) continue;
        dfs1(v, u);
        size[u] += size[v];
        if(size[v] > size[wson[u]]) wson[u] = v;
    }
}
void dfs2(int u, int topf) {
    top[u] = topf;
    if(wson[u]) dfs2(wson[u], topf);
    for(int i = head2[u]; i; i = e2[i].next) {
        int v = e2[i].to;
        if(v == wson[u] || v == fa[u]) continue;
        dfs2(v, v);
    }
}
int get_lca(int u, int v) {
    while(top[u] != top[v]) {
        if(dep[top[u]] < dep[top[v]]) std::swap(u, v);
        u = fa[top[u]];
    }
    if(dep[u] > dep[v]) std::swap(u, v);
    return u;
}
void print(int x) {
    std::vector<int> buf;
    while(x) {
        buf.push_back(x & 1);
        x >>= 1;
    }
    for(int i = buf.size() - 1; i >= 0; i--) cout << buf[i];
}
int main() {
    cin >> n >> m;
    while(m--) {
        int u, v; cin >> u >> v;
        link(u, v), link(v, u);
    }
    for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i, 0);
    // print array col
    //for(int i = 1; i <= n; i++) cout << col[i] << ' ';
    //cout << endl;
    for(int u = 1; u <= n; u++) {
        for(int i = head[u]; i; i = e[i].next) {
            int v = e[i].to;
            if(col[u] != col[v]) {
                link2(col[u], col[v]);
                // print the new tree
                //cout << col[u] << ' ' << col[v] << endl;
            }
        }
    }
    dfs1(1, 0); dfs2(1, 1);
    cin >> q;
    while(q--) {
        int u, v; cin >> u >> v;
        u = col[u], v = col[v];
        int lca = get_lca(u, v);
        //cout << dep[u] - dep[lca] + dep[v] - dep[lca] + 1 << endl;
        print(dep[u] - dep[lca] + dep[v] - dep[lca] + 1);
        cout << endl;
    }
    return 0;
}

转载于:https://www.cnblogs.com/Garen-Wang/p/10349196.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 防止作弊的API主要分为两种类型,一种是基于硬件的防作弊API,另一种是基于软件的防作弊API。 基于硬件的防作弊API主要包括: 1. 时钟校准API:可以检测到CPU时钟的变化,防止玩家通过修改时钟来作弊。 2. 唯一设备标识符API:可以生成唯一的设备标识符,防止玩家使用多个账号或者设备进行作弊。 3. 加密API:可以对游戏的数据进行加密,防止玩家通过篡改游戏数据来作弊。 基于软件的防作弊API主要包括: 1. 内存检测API:可以检测到玩家修改游戏内存的行为,防止玩家通过修改内存来作弊。 2. 程序完整性检测API:可以检测到程序被修改或者篡改的行为,防止玩家通过修改程序来作弊。 3. 行为检测API:可以检测到玩家的不正常行为,例如速度过快、跳跃过高等行为,防止玩家通过改变游戏行为来作弊。 总的来说,防止作弊的API需要综合使用多种技术,包括硬件和软件方面的技术,才能达到最好的效果。 ### 回答2: 防止作弊的API可以使用以下几种方法: 1. 限制请求频率:通过API管理工具,限制每个用户或IP地址的请求频率,防止恶意用户通过快速的请求进行作弊。 2. 用户认证和授权:要求用户使用API时进行身份认证,并通过授权机制限制只有有效用户可以访问API。可以使用OAuth等授权框架实现。 3. 验证码:在敏感操作或需要保护的接口上,引入验证码机制,要求用户输入验证码才能完成请求。这样可以防止自动化脚本或机器人进行作弊。 4. 接口加密和数字签名:通过在请求中加入加密或签名参数,确保请求的完整性和安全性,防止中间人攻击或篡改请求数据。 5. IP地址过滤和黑名单:通过对IP地址进行过滤和黑名单设置,屏蔽已知的恶意IP地址,减少恶意访问和作弊行为。 6. 使用机器学习算法检测异常行为:通过收集和分析API访问数据,使用机器学习算法识别异常行为,如频繁切换IP,大量请求错误信息等,及时发现可能的作弊行为。 7. API访问日志和监控:记录和监控所有API的访问日志,及时发现异常请求和异常行为,进行及时相应和调整。 需要根据实际应用场景和需求选择合适的防作弊措施,组合使用上述API可以最大限度地提高防作弊效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值