码迷,mamicode.com
首页 > 其他好文 > 详细

Educational Codeforces Round 54 (Rated for Div.2)

时间:2018-11-16 17:24:48      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:树状数组   复杂度   保留   ati   str   name   begin   \n   cond   

Educational Codeforces Round 54 (Rated for Div.2)


D. Edge Deletion

题意:一张n个点的无向图,保留其中k条边,使得有尽可能多的点与1的最短路长度不变。

做法:求出最短路树,然后自底向上删边即可。

#include <bits/stdc++.h>
#define pb push_back
#define P pair<ll,int>
typedef long long ll;
const ll inf = 1e18;
const int N = 3e5 + 7;
using namespace std;
int n, m , k;
struct edge{
    int e,nxt,id; ll w;
}E[N<<1],E2[N<<1];
int h[N], cc, h2[N],cc1;
void add(int u,int v,ll w,int d) {
    E[cc].e = v; E[cc].w = w; E[cc].id = d;
    E[cc].nxt = h[u]; h[u] = cc; ++cc;
}
void add2(int u,int v,ll w,int d) {
    E2[cc1].e = v; E2[cc1].w = w; E2[cc1].id = d;
    E2[cc1].nxt = h2[u]; h2[u] = cc1; ++cc1;
}
struct node{
    int x;ll d;
    node(){}node(int a,ll b){x=a;d=b;}
    bool operator < (const node a)const {
        return a.d < d;
    }
};
ll dis[N];
int vis[N], fa[N], fr[N];
void dij() {
    for(int i=1;i<=n;++i)dis[i]=inf;
    priority_queue<node> q;
    q.push(node(1,0));
    dis[1]=0; fa[1] = 0; fr[1] = -1;
    while(!q.empty()) {
        node tmp = q.top(); q.pop();
        int u=tmp.x;
        if(vis[u])continue;
        vis[u]=1;
        for(int i=h[u];~i;i=E[i].nxt) {
            int v=E[i].e;
            if(dis[v]>dis[u]+E[i].w) {
                dis[v]=dis[u]+E[i].w;
                fa[v] = u;
                fr[v] = E[i].id;
                q.push(node(v,dis[v]));
            }
        }
    }
    return;
}
struct node2{
    int u,v,id; ll w;
    node2(){}
    node2(int a,int b,ll c, int d) {
        u=a; v = b; w = c; id = d;
    }
};
node2 A[N];

int dep[N];
void bfs() {
    queue<int> q;
    memset(dep,-1,sizeof(dep));
    q.push(1); dep[1] = 0;
    while(!q.empty()) {
        int u = q.front(); q.pop();
        for(int i = h2[u]; ~i ; i = E2[i].nxt) {
            int v = E2[i].e;
            if(dep[v] == -1) {
                dep[v] = dep[u] + 1;
                q.push(v);
            }
        }
    }
}

vector< P > B;
int vis2[N];
int main() {
    scanf("%d%d%d",&n,&m,&k);
    memset(h,-1,sizeof(h));
    memset(h2,-1,sizeof(h2));
    for(int i = 1; i <= m; ++i) { int u,v; ll w;
        scanf("%d%d%lld",&u,&v,&w);
        A[i] = node2(u,v,w,i);
        add(u,v,w,i); add(v,u,w,i);
    }
    dij();
    for(int i = 2; i <= n; ++i) {
        int p = fr[i];
        vis2[p] = 1;
        add2(A[p].u,A[p].v,A[p].w,A[p].id);
        add2(A[p].v,A[p].u,A[p].w,A[p].id);
    }
    int e = n-1;
    bfs();
    for(int i = 2; i <= n; ++i) B.pb(P(dep[i],i));
    sort(B.begin(),B.end());
    for(int i = (int)B.size()-1; i >= 0; --i) {
        if(e > k) {
            vis2[fr[B[i].second]] = 0;
            --e;
        }
    }
    printf("%d\n",e);
    for(int i = 1; i <= m; ++i) if(vis2[i]) printf("%d ",i); puts("");
}

E. Vasya and a Tree

题意:给定一颗树,进行m个操作,每次将节点v子树中向下d+1层,的点全部加x,操作完成后询问每个点的值。

做法:dfs这棵树的同时,树状数组维护对应深度的影响,退出递归时,还原现场即可,类似于树上逆序对,因为操作的总和为m所以复杂度有保证。kd-tree和二维树状数组,都没卡过去。。。

#include <bits/stdc++.h>
#define pb push_back
#define fr first
#define sc second
#define P pair<int,ll>
typedef long long ll;
const int N = 300100;
using namespace std;
int n, m;
int dep[N],MX;
vector<int> G[N];
vector< P > A[N];
ll B[N], ans[N<<1];
void add(int x,ll v) {
    x += 10;
    for(int i=x;i;i-=(i&-i)) B[i] += v;
}
ll ask(int x) {
    ll ans = 0;
    x += 10;
    for(int i = x; i <= MX+20; i+=(i&(-i))) ans += B[i];
    return ans;
}
void dfs(int u,int fa) {
    dep[u] = dep[fa] + 1;
    MX = max(dep[u],MX);
    for(int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i];
        if(v != fa) dfs(v,u);
    }
}
void dfs2(int u,int fa) {
    for(int i = 0; i < A[u].size(); ++i) add(A[u][i].fr,A[u][i].sc);
    ans[u] = ask(dep[u]);
    for(int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i];
        if(v != fa) {
            dfs2(v,u);
        }
    }
    for(int i = 0; i < A[u].size(); ++i) add(A[u][i].fr,-A[u][i].sc);
}
int main() {
    scanf("%d",&n);
    for(int i = 1; i <= n-1; ++i) { int u,v;
        scanf("%d%d",&u,&v);
        G[u].pb(v); G[v].pb(u);
    }
    dep[0] = -1;
    dfs(1,0);
    scanf("%d",&m);
    for(int i = 1; i <= m; ++i) { int v,d; ll x;
        scanf("%d%d%lld",&v,&d,&x);
        A[v].pb(P(min(dep[v]+d,MX),x));
    }
    dfs2(1,0);
    for(int i = 1; i <= n; ++i)
        printf("%lld ",ans[i]);puts("");
    return 0;
}

Educational Codeforces Round 54 (Rated for Div.2)

标签:树状数组   复杂度   保留   ati   str   name   begin   \n   cond   

原文地址:https://www.cnblogs.com/RRRR-wys/p/9969644.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!