【LOJ】#2270. 「SDOI2017」天才黑客
2018-10-03 19:51
260 查看
题解
显然要记录每个点来的状态,这样会扩充出点度的平方条边,就gg了
删掉所有的点,把每个边拆成两个点,连一条边权为c
这个时候我们考虑对于原先的每个点,将所有与其相连边所需要的节点(不管是进入还是出去)建一棵虚树,然后用线段树优化建图,优化方法是枚举每个lca,然后将lca的每个子树和其他子树连一条长度为lca深度的边,也就是dfs序上连续的一段
进到这个点的边拆出来的点和负责出去的线段树的子节点连一条边
负责进来的线段树向这个点出去的节点连一条边
跑最短路就行
然后就做完了……
写的我真累= =
我非常好奇到底如何能只写3.xK????
update:貌似有更清奇的写法不用线段树orzzzzz
代码
(7.6K的sd代码,不看也罢)
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define enter putchar('\n') #define space putchar(' ') //#define ivorysi #define MAXN 200005 #define MAXK 80005 typedef long long int64; using namespace std; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } int N,M,K; priority_queue<pair<int64,int> > Q; namespace Tree { struct node { int next,to; }E[MAXK * 2]; int head[MAXK],sumE,dfn[MAXK],idx,dep[MAXK]; int st[MAXK * 2][17],len[MAXK * 2],pos[MAXK],tot; void add(int u,int v) { E[++sumE].next = head[u]; E[sumE].to = v; head[u] = sumE; } int min_dep(int a,int b) { return dep[a] < dep[b] ? a : b; } int lca(int a,int b) { a = pos[a];b = pos[b]; if(a > b) swap(a,b); int l = len[b - a + 1]; return min_dep(st[a][l],st[b - (1 << l) + 1][l]); } void dfs(int u,int fa) { dfn[u] = ++idx; st[++tot][0] = u;pos[u] = tot;dep[u] = dep[fa] + 1; for(int i = head[u] ; i ; i = E[i].next) { int v = E[i].to; if(v != fa) { dfs(v,u); st[++tot][0] = u; } } } void Init() { sumE = 0;memset(head,0,sizeof(head));idx = 0; memset(st,0,sizeof(st)); int u,v,w; for(int i = 1 ; i < K ; ++i) { read(u);read(v);read(w); add(u,v); } idx = 0;tot = 0; dfs(1,0); for(int i = 2 ; i <= tot ; ++i) len[i] = len[i / 2] + 1; for(int j = 1 ; j <= 16 ; ++j) { for(int i = 1 ; i <= tot ; ++i) { st[i][j] = min_dep(st[i][j - 1],st[i + (1 << j - 1)][j - 1]); } } } } namespace Graph { struct node { int next,to; int64 val; }E[4000005]; int head[1000005],sumE,pos[1000005],Ncnt,S; vector<int> vec[MAXN][2]; int Line[200005],tot,sta[MAXK],top,faAux[MAXK],siz[MAXK],d[MAXK],pz[2][MAXK],tr[2][MAXK * 8]; int64 dis[1000005]; bool vis[1000005]; bool cmp(int a,int b) { return Tree::dfn[a] < Tree::dfn[b]; } void add(int u,int v,int64 c) { E[++sumE].to = v; E[sumE].next = head[u]; E[sumE].val = c; head[u] = sumE; } void Init() { sumE = 0;Ncnt = 0;memset(head,0,sizeof(head)); for(int i = 1 ; i <= N ; ++i) {vec[i][0].clear();vec[i][1].clear();} int a,b,d; int64 c; for(int i = 1 ; i <= M ; ++i) { read(a);read(b);read(c);read(d); pos[Ncnt + 1] = d;pos[Ncnt + 2] = d; vec[a][1].pb(Ncnt + 1);vec[b][0].pb(Ncnt + 2); add(Ncnt + 1,Ncnt + 2,c); Ncnt += 2; } S = ++Ncnt; pos[S] = 1;vec[1][0].pb(S); } void Build_SegmentTree(int id,int u,int L,int R) { tr[id][u] = ++Ncnt; if(L == R) {pz[id][Line[R]] = Ncnt;return;} int mid = (L + R) >> 1; Build_SegmentTree(id,u << 1,L,mid); Build_SegmentTree(id,u << 1 | 1,mid + 1,R); if(!id) {add(tr[id][u << 1],tr[id][u],0);add(tr[id][u << 1 | 1],tr[id][u],0);} else {add(tr[id][u],tr[id][u << 1],0);add(tr[id][u],tr[id][u << 1 | 1],0);} } void Add_Edge(int id,int u,int L,int R,int l,int r,int v,int64 c) { if(L == l && R == r) { if(!id) {add(tr[id][u],v,c);} else {add(v,tr[id][u],c);} return; } int mid = (L + R) >> 1; if(r <= mid) Add_Edge(id,u << 1,L,mid,l,r,v,c); else if(l > mid) Add_Edge(id,u << 1 | 1,mid + 1,R,l,r,v,c); else {Add_Edge(id,u << 1,L,mid,l,mid,v,c);Add_Edge(id,u << 1 | 1,mid + 1,R,mid + 1,r,v,c);} } void Build_AuxTree() { top = 0; sta[++top] = Line[1];faAux[Line[1]] = 0; int c = tot; for(int i = 2 ; i <= c ; ++i) { int f = Tree::lca(sta[top],Line[i]); while(top >= 1 && Tree::dep[sta[top]] > Tree::dep[f]) { if(top == 1 || Tree::dep[sta[top - 1]] <= Tree::dep[f]) { faAux[sta[top]] = f; } --top; } if(f != sta[top]) { faAux[f] = sta[top]; sta[++top] = f; Line[++tot] = f; } sta[++top] = Line[i]; faAux[Line[i]] = f; } sort(Line + 1,Line + tot + 1,cmp); for(int i = 1 ; i <= tot ; ++i) siz[Line[i]] = 1; for(int i = tot ; i >= 1 ; --i) { siz[faAux[Line[i]]] += siz[Line[i]]; d[Line[i]] = i; } Build_SegmentTree(0,1,1,tot); Build_SegmentTree(1,1,1,tot); for(int i = 1 ; i <= tot ; ++i) { int u = Line[i]; ++Ncnt; Add_Edge(0,1,1,tot,i,i,Ncnt,Tree::dep[u] - 1); Add_Edge(1,1,1,tot,i,i + siz[u] - 1,Ncnt,0); int f = faAux[u]; if(f) { ++Ncnt; Add_Edge(0,1,1,tot,i,i + siz[u] - 1,Ncnt,Tree::dep[f] - 1); if(d[f] <= i - 1) Add_Edge(1,1,1,tot,d[f],i - 1,Ncnt,0); if(d[f] + siz[f] - 1 >= i + siz[u]) Add_Edge(1,1,1,tot,i + siz[u],d[f] + siz[f] - 1,Ncnt,0); } } } void Build_Graph() { for(int i = 1 ; i <= N ; ++i) { tot = 0; for(int k = 0 ; k <= 1 ; ++k) { for(int j = 0 ; j < vec[i][k].size() ; ++j) { Line[++tot] = pos[vec[i][k][j]]; } } sort(Line + 1,Line + tot + 1); tot = unique(Line + 1,Line + tot + 1) - Line - 1; sort(Line + 1,Line + tot + 1,cmp); Build_AuxTree(); for(int k = 0 ; k <= 1 ; ++k) { for(int j = 0 ; j < vec[i][k].size() ; ++j) { int t = vec[i][k][j]; if(!k) add(t,pz[k][pos[t]],0); else add(pz[k][pos[t]],t,0); } } } } void Dijkstra() { for(int i = 1 ; i <= Ncnt ; ++i) { dis[i] = 1e16;vis[i] = 0; } dis[S] = 0; Q.push(mp(-dis[S],S)); while(!Q.empty()) { pair<int64,int> now = Q.top();Q.pop(); int u = now.se; if(vis[u]) continue; vis[u] = 1; for(int i = head[u] ; i; i = E[i].next) { int v = E[i].to; if(dis[v] > dis[u] + E[i].val) { dis[v] = dis[u] + E[i].val; Q.push(mp(-dis[v],v)); } } } } void Print() { for(int i = 2 ; i <= N ; ++i) { int64 ans = 1e16; for(int j = 0 ; j < vec[i][0].size() ; ++j) ans = min(ans,dis[vec[i][0][j]]); out(ans);enter; } } } void Solve() { read(N);read(M);read(K); Graph::Init(); Tree::Init(); Graph::Build_Graph(); Graph::Dijkstra(); Graph::Print(); } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif int T; read(T); while(T--) Solve(); return 0; }
md我zz吧
我代码是别人的两倍,运行时间也是别人的两倍啊
我附加点为什么最后都建到1000000去了,不应该啊,然后还0.5s?是LOJ的评测机扩充了我的想象力吗
好写???
没觉得好写啊???
我觉得刷新了我难写的上限啊???
思路和细节写的比NOI2018D2T2还累啊,我代码能力难道真的退化了???
相关文章推荐
- bzoj 4912: [Sdoi2017]天才黑客 最短路+dfs序优化建图
- bzoj 4912: [Sdoi2017]天才黑客
- [最短路 虚树+线段树优化建图] BZOJ 4912 [Sdoi2017]天才黑客
- BZOJ4912 : [Sdoi2017]天才黑客
- LOJ刷题记录:2000-2005(SDOI2017)
- 【LOJ】#2268. 「SDOI2017」苹果树
- 【LOJ】#2269. 「SDOI2017」切树游戏
- 黑掉微软的14岁天才黑客 接受训练改邪归正
- LOJ 「SDOI2017」新生舞会(二分 + 分数规划+ 费用流)
- LOj 2000「SDOI2017」数字表格 (莫比乌斯反演)
- 美国天才黑客自杀:构建知识共享的世界
- 17岁少年黑客成诈骗案主犯, 警察:称他为天才一点不为过
- 电脑黑客或电脑天才方面的电影
- 天才黑客!17岁打脸乔布斯,20岁搞疯索尼,26岁叫板特斯拉,写2000行代码市值8000万美金
- 22岁黑客天才破译iPod保护代码
- 天才黑客打脸乔布斯玩转索尼叫板特斯拉!
- 19岁天才黑客发布首个iPhone 3GS破解软件
- BZOJ4912 [Sdoi2017]天才黑客 【虚树 + 最短路】
- 17岁少年黑客成诈骗案主犯, 警察:称他为天才一点不为过
- 黑客专访:天才黑客Gabriel Bergel的黑客人生