2017-2018 ACM-ICPC Northern Eurasia (Northeastern European Regional) Contest (NEERC 17)

2017-2018 ACM-ICPC Northern Eurasia (Northeastern European Regional) Contest (NEERC 17)

A.Archery Tournament

假设当前询问为(x,y),那么能包含它的圆必然是其左边第一个直径(ge y)的或者其右边第一个直径(ge y)的,可以离线下来用线段树来找这两个圆,再判断一下点在不在圆内,先离散化所有点的横坐标,每个圆再线段树中的位置就以其离散化之后的(x)为基准

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
using LL = int_fast64_t;
const int MAXN = 2e5+7;
int n;
vector<int> vec;
struct SegmentTree{
    int maxx[MAXN<<2], l[MAXN<<2], r[MAXN<<2], ID[MAXN<<2];
    #define ls(rt) rt << 1
    #define rs(rt) rt << 1 | 1
    void pushup(int rt){ maxx[rt] = max(maxx[ls(rt)], maxx[rs(rt)]); }
    void build(int L, int R, int rt){
        l[rt] = L, r[rt] = R;
        maxx[rt] = ID[rt] = 0;
        if(L + 1 == R) return;
        int mid = (L + R) >> 1;
        build(L,mid,ls(rt)); build(mid,R,rs(rt));
    }
    void update(int pos, int rt, int id, int y){
        if(l[rt] + 1 == r[rt]){
            maxx[rt] = y;
            ID[rt] = id;
            return;
        }
        int mid = (l[rt] + r[rt]) >> 1;
        if(pos<mid) update(pos,ls(rt),id,y);
        else update(pos,rs(rt),id,y);
        pushup(rt);
    }
    int QL(int x, int y, int rt){
        if(l[rt]>x or maxx[rt]<y) return -1;
        if(l[rt]+1==r[rt]) return ID[rt];
        int ret = QL(x,y,rs(rt));
        if(ret!=-1) return ret;
        else return QL(x,y,ls(rt));
    }
    int QR(int x, int y, int rt){
        if(r[rt]<=x or maxx[rt]<y) return -1;
        if(l[rt]+1==r[rt]) return ID[rt];
        int ret = QR(x,y,ls(rt));
        if(ret!=-1) return ret;
        else return QR(x,y,rs(rt));
    }
}ST;
pair<int,pair<int,int>> Q[MAXN];
bool shoot(const pair<int,int> &sp, int p){
    pair<int,int> O = Q[p].second;
    if(1ll*O.second*O.second > (O.first-sp.first) * 1ll * (O.first-sp.first) + (O.second-sp.second) * 1ll *(O.second-sp.second)){
        ST.update(lower_bound(vec.begin(),vec.end(),Q[p].second.first)-vec.begin()+1,1,0,0);
        return true;
    }
    return false;
}
int main(){
    ____();
    cin >> n;
    ST.build(1,n+1,1);
    for(int i = 1; i <= n; i++){
        cin >> Q[i].first >> Q[i].second.first >> Q[i].second.second;
        vec.emplace_back(Q[i].second.first);
    }
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    for(int i = 1; i <= n; i++){
        if(Q[i].first==1) ST.update(lower_bound(vec.begin(),vec.end(),Q[i].second.first)-vec.begin()+1,1,i,Q[i].second.second<<1);
        else{
            int nx = lower_bound(vec.begin(),vec.end(),Q[i].second.first) - vec.begin() + 1;
            int p = ST.QL(nx,Q[i].second.second,1);
            bool ok = false;
            if(p!=-1) ok = shoot(Q[i].second,p);
            if(!ok){
                p = ST.QR(nx,Q[i].second.second,1);
                if(p!=-1) ok = shoot(Q[i].second,p);
            }
            if(ok) cout << p << endl;
            else cout << -1 << endl;
        }
    }
    return 0;
}

B.Box

枚举判断即可

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
int a,b,c,w,h;
bool check(int n, int m){
    if((a+b)*2<=n and (c+2*a<=m or c+2*b<=m)) return true;
    if((a+c)*2<=n and (b+2*a<=m or b+2*c<=m)) return true;
    if((b+c)*2<=n and (a+2*b<=m or a+2*c<=m)) return true;
    if(3*a+b+c<=n and b+c <= m) return true;
    if(3*b+a+c<=n and a+c <= m) return true;
    if(3*c+a+b<=n and a+b <= m) return true;
    return false;
}
int main(){
    ____();
    cin >> a >> b >> c >> w >> h;
    if(check(w,h) or check(h,w)) cout << "Yes" << endl;
    else cout << "No" << endl;
    return 0;
}

C.Connections

给出一张强连通图,要求保留(2n)条边,剩下的图仍然强连通
(1)点跑一遍图,然后边取反,再对(1)点跑一遍图,经过的边即为剩下的,且最多有(2n-2)条,补到(2n)条即可
跑完之后选的边使得(1)号点可以到达任何点,同时任何点可以到达(1)号点,所以保证强连通

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e5+7;
vector<pair<int,int> > G[MAXN], rG[MAXN];
int n,m;
pair<int,int> edge[MAXN];
bool vis[MAXN],used[MAXN];
void dfs(int u, bool rev){
    vis[u] = true;
    for(auto e : (rev?rG[u]:G[u])){
        if(!vis[e.first]){
            used[e.second] = true;
            dfs(e.first,rev);
        }
    }
}
void solve(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++){
        G[i].clear();
        rG[i].clear();
    }
    for(int i = 1; i <= m; i++){
        cin >> edge[i].first >> edge[i].second;
        int u = edge[i].first, v = edge[i].second;
        G[u].emplace_back(make_pair(v,i));
        rG[v].emplace_back(make_pair(u,i));
        used[i] = false;
    }
    for(int i = 1; i <= n; i++) vis[i] = false;
    dfs(1,false);
    for(int i = 1; i <= n; i++) vis[i] = false;
    dfs(1,true);
    int cnt = 0;
    for(int i = 1; i <= m; i++){
        if(!used[i]){
            cnt++;
            cout << edge[i].first  << ' ' << edge[i].second << endl;
        }
        if(cnt==m-2*n) break;
    }
}
int main(){
    ____();
    int T;
    for(cin >> T; T; T--) solve();
    return 0;
}

D.Designing the Toy

给定三视图的面积,要求构造出一个立体图形满足条件,允许方块不叠在一起。
可以发现如果小的两个的乘积比大的还小是必然构造不了的,否则必然能够构造出一个某一个维度宽度为1的立体图形。
具体构造看代码,注意坐标的转换

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 111;
int a[3],b[3],match[3];
bool done[MAXN][MAXN];
int main(){
    cin >> a[0] >> a[1] >> a[2];
    b[0] = a[0]; b[1] = a[1]; b[2] = a[2];
    sort(b,b+3);
    if(b[0]*b[1]<b[2]){
        cout << -1 << endl;
        return 0;
    }
    cout << b[2] << endl;
    for(int i = 1; i <= b[0]; i++) done[i][i] = true;
    for(int i = b[0] + 1; i <= b[1]; i++) done[1][i] = true;
    int delta = b[2] - b[1];
    for(int i = 1; i <= b[0]; i++) for(int j = 1; j <= b[1]; j++){
        if(!delta) break;
        if(done[i][j]) continue;
        delta--; done[i][j] = true;
    }
    for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++){
        if(a[i]==b[j]){
            b[j] = -1, match[i] = j;
            break;
        }
    }
    for(int i = 0; i < MAXN; i++) for(int j = 0; j < MAXN; j++){
        if(!done[i][j]) continue;
        if(match[0]==2){
            if(match[1]==0) cout << i << ' ' << j << ' ' << 1 << endl;
            else cout << j << ' ' << i << ' ' << 1 << endl;
        }
        else if(match[1]==2){
            if(match[0]==0) cout << i << ' ' << 1 << ' ' << j << endl;
            else cout << j << ' ' << 1 << ' ' << i << endl;
        }
        else{
            if(match[0]==0) cout << 1 << ' ' << i << ' ' << j << endl;
            else cout << 1 << ' ' << j << ' ' << i << endl;
        }
    }
    return 0;
}

E.Easy Quest

简单签到

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1111;
int n,A[MAXN];
vector<int> vec;
int main(){
    ____();
    cin >> n;
    for(int i = 1; i <= n; i++){
        int x; cin >> x;
        if(x>=0) A[x]++;
        else{
            if(A[-x]) A[-x]--;
            else{
                if(A[0]) A[0]--, vec.emplace_back(-x);
                else{
                    cout << "No" << endl;
                    return 0;
                }
            }
        }
    }
    while(A[0]) A[0]--, vec.emplace_back(1);
    cout << "Yes" << endl;
    for(int x : vec) cout << x << ' '; cout << endl;
    return 0;
}

F.The Final Level

分四种情况枚举判断一下,要记录一下上一次放的最后一个位置和当前位置的相对位置,先把坐标转换成正的,最后在转换回去

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
int a,b,n,fa,fb;
vector<pair<pair<int,int>,pair<int,int>>> ret;
ostream& operator << (ostream &os, const pair<pair<int,int>,pair<int,int>> pr){
    os << pr.first.first*fa << ' ' << pr.first.second*fb << ' ' << pr.second.first*fa << ' ' << pr.second.second*fb;
    return os;
}
void dfs(int ca, int cb, int vert){
    int dx = a - ca, dy = b - cb;
    if(dx<n and dy < n){
        if(vert) ret.emplace_back(make_pair(make_pair(ca+dx,cb+n-1),make_pair(ca-(n-1-dx),cb)));
        else ret.emplace_back(make_pair(make_pair(ca,cb-(n-1-dy)),make_pair(ca+n-1,cb+dy)));
        return;
    }
    else if(dx<n){        
        ret.emplace_back(make_pair(make_pair(ca,cb),make_pair(ca+n-1,cb+n-1)));
        dfs(a,cb+n,1);
    }
    else if(dy<n){
        ret.emplace_back(make_pair(make_pair(ca+n-1,cb+n-1),make_pair(ca,cb)));
        dfs(ca+n,b,0);
    }
    else{
        ret.emplace_back(make_pair(make_pair(ca,cb),make_pair(ca+n-1,cb+n-1)));
        if(dx<dy) dfs(ca+n-1,cb+n,1);
        else dfs(ca+n,cb+n-1,0);
    }
}
void solve(){
    cin >> a >> b >> n;
    a = a * (fa = a < 0 ? -1 : 1);
    b = b * (fb = b < 0 ? -1 : 1);
    ret.clear();
    dfs(0,0,1);
    cout << ret.size() << endl;
    for(auto p : ret) cout << p << endl;
}
int main(){
    ____();
    int T; for(cin >> T; T; T--) solve();    
    return 0;
}

G.The Great Wall

H.Hack

I.Interactive Sort

J.Journey from Petersburg to Moscow

给出一张图,求(1)(n)的最短路,其中如果经过的路径超过(k)条,只选择前(k)条的花费
枚举第(k+1)条边的长度(x),建图时边的长度变成(max(0,w-x)),最后答案为(dist[n]+kcdot x),找最小值即可

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
using LL = int_fast64_t;
const int MAXN = 3333;
int n,m,k;
vector<pair<int,int>> G[MAXN];
LL dist[MAXN];
LL Dijkstra(int x){
    memset(dist,0x3f,sizeof(dist));
    dist[1] = 0;
    priority_queue<pair<LL,int>,vector<pair<LL,int>>,greater<pair<LL,int>>> que;
    que.push(make_pair(dist[1],1));
    while(!que.empty()){
        auto p = que.top();
        que.pop();
        int u = p.second;
        LL d = p.first;
        if(dist[u]!=d) continue;
        for(auto e : G[u]){
            int v = e.first, w = max(e.second-x,0);
            if(dist[u]+w<dist[v]){
                dist[v] = dist[u] + w;
                que.push(make_pair(dist[v],v));
            }
        }
    }
    return dist[n] + 1ll * k * x;
}
int main(){
    scanf("%d %d %d",&n,&m,&k);
    vector<int> vec;
    for(int i = 1; i <= m; i++){
        int u, v, w;
        scanf("%d %d %d",&u,&v,&w);
        G[u].emplace_back(make_pair(v,w));
        G[v].emplace_back(make_pair(u,w));
        vec.emplace_back(w);
    }
    vec.emplace_back(0);
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    LL ret = INT64_MAX;
    for(int x : vec) ret = min(ret,Dijkstra(x));
    printf("%I64d
",ret);
    return 0;
}

K.Knapsack Cryptosystem

L.Laminar Family

给定一棵树和其中的一些链,问是否任何两条链只存在包含或者交集为(0)的情况
树链剖分,以(lca)深度为第一关键字,链长为第二关键字排序所有的链,这样能保证之后的链不可能包含之前的链,只要考虑之后的链是否和之前的链相交即可
然后找链上最小值和最大值,判断是否相等
每次找完之后链上各点权值+1

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e5+7;
const int INF = 0x3f3f3f3f;
vector<int> G[MAXN];
int n,m,dfn[MAXN],rdfn[MAXN],depth[MAXN],son[MAXN],top[MAXN],sz[MAXN],par[MAXN][20],idx;
struct SegmentTree{
    int minn[MAXN<<2],maxx[MAXN<<2],l[MAXN<<2],r[MAXN<<2],lazy[MAXN<<2];
    #define ls(rt) rt << 1
    #define rs(rt) rt << 1 | 1
    void pushup(int rt){
        minn[rt] = min(minn[ls(rt)],minn[rs(rt)]);
        maxx[rt] = max(maxx[ls(rt)],maxx[rs(rt)]);
    }
    void build(int L, int R, int rt = 1){
        l[rt] = L; r[rt] = R;
        if(L+1==R) return;
        int mid = (L+R) >> 1;
        build(L,mid,ls(rt)); build(mid,R,rs(rt));
    }
    void pushdown(int rt){
        if(!lazy[rt]) return;
        lazy[ls(rt)] += lazy[rt]; lazy[rs(rt)] += lazy[rt];
        minn[ls(rt)] += lazy[rt]; minn[rs(rt)] += lazy[rt];
        maxx[ls(rt)] += lazy[rt]; maxx[rs(rt)] += lazy[rt];
        lazy[rt] = 0;
    }
    int QMIN(int L, int R, int rt = 1){
        if(l[rt]>=R or L>=r[rt]) return INF;
        if(L<=l[rt] and r[rt]<=R) return minn[rt];
        pushdown(rt);
        return min(QMIN(L,R,ls(rt)),QMIN(L,R,rs(rt)));
    }
    int QMAX(int L, int R, int rt = 1){
        if(l[rt]>=R or L>=r[rt]) return 0;
        if(L<=l[rt] and r[rt]<=R) return maxx[rt];
        pushdown(rt);
        return max(QMAX(L,R,ls(rt)),QMAX(L,R,rs(rt)));
    }
    void update(int L, int R, int rt = 1){
        if(l[rt]>=R or L>=r[rt]) return;
        if(L<=l[rt] and r[rt]<=R){
            lazy[rt]++; maxx[rt]++; minn[rt]++;
            return;
        }
        pushdown(rt);
        update(L,R,ls(rt)); update(L,R,rs(rt));
        pushup(rt);
    }
}ST;
void modify(int u, int v){
    while(top[u]!=top[v]){
        if(depth[top[u]]<depth[top[v]]) swap(u,v);
        ST.update(dfn[top[u]],dfn[u]+1);
        u = par[top[u]][0];
    }
    if(depth[u]<depth[v]) swap(u,v);
    ST.update(dfn[v],dfn[u]+1);
}
int qmin(int u, int v){
    int minn = INF;
    while(top[u]!=top[v]){
        if(depth[top[u]]<depth[top[v]]) swap(u,v);
        minn = min(minn,ST.QMIN(dfn[top[u]],dfn[u]+1));
        u = par[top[u]][0];
    }
    if(depth[u]<depth[v]) swap(u,v);
    return min(minn,ST.QMIN(dfn[v],dfn[u]+1));
}
int qmax(int u, int v){
    int maxx = 0;
    while(top[u]!=top[v]){
        if(depth[top[u]]<depth[top[v]]) swap(u,v);
        maxx = max(maxx,ST.QMAX(dfn[top[u]],dfn[u]+1));
        u = par[top[u]][0];
    }
    if(depth[u]<depth[v]) swap(u,v);
    return max(maxx,ST.QMAX(dfn[v],dfn[u]+1));
}
bool check(int u, int v){ return qmax(u,v)==qmin(u,v); }
void dfs1(int u, int f){
    sz[u] = 1; depth[u] = depth[par[u][0] = f] + 1;
    for(int i = 1; par[u][i-1]; i++) par[u][i] = par[par[u][i-1]][i-1];
    for(int v : G[u]){
        if(v==f) continue;
        dfs1(v,u); sz[u] += sz[v];
        if(sz[v]>sz[son[u]]) son[u] = v;
    }
}
void dfs2(int u, int tp){
    dfn[u] = ++idx; rdfn[idx] = u;
    top[u] = tp;
    if(son[u]) dfs2(son[u],tp);
    for(int v : G[u]){
        if(v==par[u][0] or v==son[u]) continue;
        dfs2(v,v);
    }
}
int LCA(int u, int v){
    if(depth[u]<depth[v]) swap(u,v);
    for(int i = 0; i < 20; i++) if((depth[u]-depth[v])&(1<<i)) u = par[u][i];
    if(u==v) return u;
    for(int i = 19; i >= 0; i--) if(par[u][i]!=par[v][i]){
        u = par[u][i];
        v = par[v][i];
    }
    return par[u][0];
}
int main(){
    ____();
    cin >> n >> m;
    for(int i = 1; i < n; i++){
        int u, v; cin >> u >> v;
        G[u].emplace_back(v);
        G[v].emplace_back(u);
    }
    dfs1(1,0); dfs2(1,1);
    vector<pair<pair<int,int>,pair<int,int>>> vec(m);
    for(int i = 0; i < m; i++){
        cin >> vec[i].second.first >> vec[i].second.second;
        int lca = LCA(vec[i].second.first,vec[i].second.second);
        vec[i].first.first = lca;
        vec[i].first.second = depth[vec[i].second.first] + depth[vec[i].second.second] - 2 * depth[lca];
    }
    sort(vec.begin(),vec.end(),[](const pair<pair<int,int>,pair<int,int>> &lhs, const pair<pair<int,int>,pair<int,int>> &rhs){
        if(depth[lhs.first.first]==depth[rhs.first.first]) return lhs.first.second > rhs.first.second;
        else return depth[lhs.first.first] < depth[rhs.first.first];
    });
    ST.build(1,MAXN);
    for(auto pr : vec){
        if(!check(pr.second.first,pr.second.second)){
            cout << "No" << endl;
            return 0;
        }
        modify(pr.second.first,pr.second.second);
    }
    cout << "Yes" << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/kikokiko/p/12670798.html