Educational Codeforces Round 54 (Rated for Div.2)
阿新 • • 發佈:2018-11-16
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; }