题解

显然要记录每个点来的状态,这样会扩充出点度的平方条边,就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还累啊,我代码能力难道真的退化了???

【LOJ】#2270. 「SDOI2017」天才黑客的更多相关文章

  1. loj#2269. 「SDOI2017」切树游戏

    还是loj的机子快啊... 普通的DP不难想到,设F[i][zt]为带上根玩出zt的方案数,G[i][zt]为子树中的方案数,后面是可以用FWT优化的 主要是复习了下动态DP #include< ...

  2. loj#2002. 「SDOI2017」序列计数(dp 矩阵乘法)

    题意 题目链接 Sol 质数的限制并没有什么卵用,直接容斥一下:答案 = 忽略质数总的方案 - 没有质数的方案 那么直接dp,设\(f[i][j]\)表示到第i个位置,当前和为j的方案数 \(f[i ...

  3. @loj - 2004@ 「SDOI2017」硬币游戏

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数 ...

  4. LOJ #2005. 「SDOI2017」相关分析 线段树维护回归直线方程

    题目描述 \(Frank\) 对天文学非常感兴趣,他经常用望远镜看星星,同时记录下它们的信息,比如亮度.颜色等等,进而估算出星星的距离,半径等等. \(Frank\) 不仅喜欢观测,还喜欢分析观测到的 ...

  5. [LOJ#2270][BZOJ4912][SDOI2017]天才黑客

    [LOJ#2270][BZOJ4912][SDOI2017]天才黑客 试题描述 SD0062 号选手小 Q 同学为了偷到 SDOI7012 的试题,利用高超的黑客技术潜入了 SDOI 出题组的内联网的 ...

  6. LibreOJ 2003. 「SDOI2017」新生舞会 基础01分数规划 最大权匹配

    #2003. 「SDOI2017」新生舞会 内存限制:256 MiB时间限制:1500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  7. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  8. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  9. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

随机推荐

  1. (转)eclipse 报错 :The method list(String, Object[]) is ambiguous for the type BaseHibernateDao

    背景:在开发过程中,经常遇到各种各样的编译问题,不断的总结,才能更好的提高效率. 描述 [报错] :The method list(String, Object[]) is ambiguous for ...

  2. mybatis与分布式事务的面试

    mybatis的面试: https://www.cnblogs.com/huajiezh/p/6415388.html 本地事务与分布式事务: https://www.cnblogs.com/xcj2 ...

  3. Codeforces 666 B. World Tour

    http://codeforces.com/problemset/problem/666/B 题意: 给定一张边权均为1的有向图,求四个不同的点A,B,C,D,使得dis[A][B]+dis[B][C ...

  4. bzoj千题计划208:bzoj3174: [Tjoi2013]拯救小矮人

    http://www.lydsy.com/JudgeOnline/problem.php?id=3174 按a+b从小到大排序,a+b小的在上面,先考虑让它逃出去 正确性不会证 感性理解一下,最后一个 ...

  5. python 基础 元组()

    # 元组 应用场景 # 尽管 Python的列表中可以存储不同类型的数据 # 但是在开发中,更多的应用场景是 # 1.列表存储相同类型的数据 # 2.通过迭代遍历,在循环体内部,针对列表中的每一项元素 ...

  6. 关于Web安全的那些事(XSS攻击)

    概述 XSS攻击是Web攻击中最常见的攻击方法之一,它是通过对网页注入可执行代码且成功地被浏览器执行,达到攻击的目的,形成了一次有效XSS攻击,一旦攻击成功,它可以获取用户的联系人列表,然后向联系人发 ...

  7. Guava HashMultiset(MultiSet)

    multiset:多重集合,和set唯一的不同是 set 集合中一个值只能出现一次,而multiset多重集合中一个值可以出现多次.一个典型的应用就是统计单词出现次数 举例: public class ...

  8. Spark笔记之使用UDF(User Define Function)

    一.UDF介绍 UDF(User Define Function),即用户自定义函数,Spark的官方文档中没有对UDF做过多介绍,猜想可能是认为比较简单吧. 几乎所有sql数据库的实现都为用户提供了 ...

  9. 【腾讯云】自己搭建的腾讯云服务器JavaEE环境

    0.安装SSH登录 1.生成公钥对 ssh-keygen -t rsa -P '' -P表示密码,-P '' 就表示空密码,也可以不用-P参数,这样就要三车回车,用-P就一次回车.它在/home/ch ...

  10. 一份最中肯的Java学习路线+资源分享(拒绝傻逼式分享)

    这是一篇针对Java初学者,或者说在Java学习路线上出了一些问题(不知道该学什么.不知道整体的学习路线是什么样的) 第一步:Java基础(一个月左右) 推荐视频: 下面的是黑马内部视频,我比较推荐的 ...