1. 程式人生 > >洛谷3783 SDOI2017 天才黑客(最短路+虛樹+邊轉點+線段樹優化建圖)

洛谷3783 SDOI2017 天才黑客(最短路+虛樹+邊轉點+線段樹優化建圖)

題目連結

成功又一次自閉了

怕不是豬國殺之後最自閉的一次

一看到最短路徑。
我們就能推測這應該是個最短路題

現在考慮怎麼建圖

根據題目的意思,我們可以發現,在本題中,邊與邊之間存在一些轉換關係,但是點與點之間並不存在。

那麼我們考慮 邊轉點,點轉邊。

每一條邊拆成兩個點,之間連邊權的邊
新建一個起點 S S ,與 1

1 號點的出邊所對應的入點連邊
然後根據原圖中一個點的入度和出度之間的關係建圖。(我們可以將 L C P LCP 視為 t
r i e trie
樹上的 L C A LCA

最後跑一遍 d i j k s t r a dijkstra ,那麼對於每個原圖中的點的最短路,就相當於所有該點的入邊的出點的 d i s dis 的最小值。

這樣樸素建圖是 O ( n 2 ) O(n^2)

顯然是接受不了的。

我們考慮怎麼優化這個過程

首先,對於一個點來說,我們只需要考慮包含它的邊的 d d ,也就是說,我們可以考慮把這些點拎出來,然後建一顆虛樹,那麼對於當前點,只有這顆虛樹上的點才是有用的。

對於一個點 x x ,他作為轉折的貢獻,當且僅當他成為兩條邊的 d d L C A LCA 的時候,那麼我們可以將它的每個兒子的子樹出點向其他兒子的子樹入點連邊,表示可以他們之間的代價是 d e e p [ x ] 1 deep[x]-1

哎?子樹?貌似子樹的 d f s dfs 序好像是連續的?是不是可以線段樹優化建圖的\xyx

沒錯,我們建立兩顆線段樹,分別表示區間連單點,和 單點連區間。
讓當前點的所有入邊的對應點連線區間連單點的對應葉子節點。出邊也是類似。

然後新建兩個點,分別讓區間連和連區間。最後再連線這兩個點,這兩個點之間的邊權是 d e e p [ x ] 1 deep[x]-1

這裡需要注意的是,每次建立線段樹的點,都要留到最後的 d i j k s t r a dijkstra ,所以這裡建議結構體封裝來做,會比較清晰一些

具體就直接看程式碼吧…
真的自閉
7.5 k 7.5k
細節特別的多

尤其是!要把各個結構體分開,不要順手寫錯了
虛樹記得自殺式遍歷
開的陣列要夠大

上程式碼

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define ll long long
#define pa pair<long long,int>
#define int long long
#define index inde
using namespace std;
inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}
const int maxn = 2e6+1e2;
const int maxm = 8e6+1e2;
int point[maxn],nxt[maxn],to[maxn];
int cnt,n,m;
int index;
int a[maxn],k;
int siz[maxn];
vector<int> in[101010],out[101010];
int deep[101010],f[101010][21];
int dnf[maxn];
int tt;
int pos[maxn];
void addedge(int x,int y,int w)
{
 nxt[++cnt]=point[x];
 to[cnt]=y;
 point[x]=cnt;
}
void dfs(int x,int fa,int dep)
{
 dnf[x]=++tt;
 deep[x]=dep;
 for (int i=point[x];i;i=nxt[i])
 {
  int p = to[i];
  if (p==fa) continue;
  f[p][0]=x;
  dfs(p,x,dep+1);
 }
}
void init()
{
 for (int j=1;j<=20;j++)
   for (int i=1;i<=k;i++)
     f[i][j]=f[f[i][j-1]][j-1];
}
int go_up(int x,int d)
{
 for (int i=0;i<=20;i++)
 {
  if ((1 << i) & d)
    x=f[x][i];
 }
 return x;
}
int lca(int x,int y)
{
 if (deep[x]>deep[y]) x=go_up(x,deep[x]-deep[y]);
 else y=go_up(y,deep[y]-deep[x]);
 if (x==y) return x;
 for (int i=20;i>=0;i--)
 {
  if (f[x][i]!=f[y][i])
  {
   x=f[x][i];
   y=f[y][i];
  }
 }
 return f[x][0];
}
struct result{
 int point[maxn],nxt[maxm],to[maxm];
 int cnt;
 int val[maxm];
 int dis[maxn],vis[maxn];
 priority_queue<pa,vector<pa>,greater<pa> > q;
 void init()
 {
    cnt=0;
    memset(point,0,sizeof(point));
 }
 void addedge(int x,int y,int w)
 {
       nxt[++cnt]=point[x];
       to[cnt]=y;
       val[cnt]=w;
       point[x]=cnt;
 }
 void dijkstra(int s)
 {
  memset(dis,127/3,sizeof(dis));
  memset(vis,0,sizeof(vis));
  dis[s]=0;
  q.push(make_pair(0,s));
  while (!q.empty())
  {
   int x = q.top().second;
   q.pop();
   if (vis[x]) continue;
   vis[x]=1;
   for (int i=point[x];i;i=nxt[i])
   {
    int p=to[i];
    if (dis[p]>dis[x]+val[i])
    {
     dis[p]=dis[x]+val[i];
     q.push(make_pair(dis[p],p));
    }
   }
  }
  } 
};
result g;
struct segment{
 int f[4*maxn],gg[4*maxn];
 int point[maxn],nxt[maxm],to[maxm];
 int dfn[maxn],back[maxn],leafout[maxn];
 int leafin[maxn];
 int tot=0;
 int cnt=0;
 int size[maxn];
 void init(){tot=0;cnt=0;}
 void addedge(int x,int y)
 {
  nxt[++cnt]=point[x];
  to[cnt]=y;
  point[x]=cnt;
 }
    void dfs(int x,int fa)
 {
     dfn[x]=++tot;
     size[x]=1;
     back[tot]=x;
     for (int i=point[x];i;i=nxt[i])
     {
      int p = to[i];
      if (p==fa) continue;
      dfs(p,x);
      size[x]+=size[p];
  }
 }
 void buildout(int root,int l,int r)
 {
     f[root]=++index;
     if (l==r)
     {
      leafout[l]=index;
      return;
  }
  int mid = l+r >> 1;
  buildout(2*root,l,mid);
  buildout(2*root+1,mid+1,r);
  g.addedge(f[2*root],f[root],0);
  g.addedge(f[2*root+1],f[root],0);
 }
 void buildin(int root,int l,int r)
 {
  gg[root]=++index;
  if (l==r)
  {
   leafin[l]=index;
   return;
  }
  int mid = l+r >> 1;
  buildin(2*root,l,mid);
  buildin(2*root+1,mid+1,r);
  g.addedge(gg[root],gg[2*root],0);
  g.addedge(gg[root],gg[2*root+1],0); 
 }
 void updateout(int root,int l,int r,int x,int y,int p)
 {
  if (x<=l && r<=y)
  {
   g.addedge(f[root],p,0);
   return;
  }
  int mid = l+r >> 1;
  if (x<=mid) updateout(2*root,l,mid,x,y,p);
  if (y>mid) updateout(2*root+1,mid+1,r,x,y,p); 
 }
 void updatein(int root,int l,int r,int x,int y,int p)
 {
  if (x<=l && r<=y)
  {
   g.addedge(p,gg[root],0);
   return;
  }
  int mid = l+r >> 1;
  if (x<=mid) updatein(2*root,l,mid,x,y,p);
  if (y>mid) updatein(2*root+1,mid+1,r,x,y,p); 
 } 
 void link(int x,int y,int xx,int yy,int w)
 {
  if (x>y || xx>yy) return;
  updateout(1,1,tot,x,y,index+1);
  updatein(1,1,tot,xx,yy,index+2);
  g.addedge(index+1,index+2,w);
  index+=2;
 } 
 void solve(int x)
 {
  dfs(1,0);
  buildout(1,1,tot);buildin(1,1,tot);
  for 
            
           

相關推薦

3783 SDOI2017 天才黑客短路+++線段優化

題目連結 成功又一次自閉了 怕不是豬國殺之後最自閉的一次 一看到最短路徑。 我們就能推測這應該是個最短路題 現在考慮怎麼建圖 根據題目的意思,我們可以發現,在本題中,邊與邊之間存在一些轉換關係,但是點與點之間並不存在。 那麼我們考慮 邊轉點,點轉邊。 每一條邊拆成

3953】逛公園短路+記憶化搜尋

點此看題面 大致題意: 有一張有NNN個點和MMM條邊組成的有向圖,若從111號點到NNN號點的最短路徑長度為ddd,問有多少條從111號點到NNN號點的路徑長度不超過d+Kd+Kd+K。若有無數條輸出

2018.10.10【CQOI2015】【BZOJ3931】【P3171】網路吞吐量短路大流

洛谷傳送門 解析: 好粗暴的最短路加最大流。。。 思路: 首先題目要求資料沿最短路傳遞,而且題目都說了DijkstraDijkstraDijkstra,怎麼還有人寫SPFASPFASPFA,不怕被卡嗎? 於是,我們先DijkstraDijkstraDijks

CF1007D. Ants鏈剖分+線段+2-SAT及字首優化

題目連結 https://codeforces.com/problemset/problem/1007/D 題解 由於問題的本質是給定許多二元集合,判斷是否能從每一個二元集合中選出一個元素,使得所有選出的元素合法,因此考慮使用 2-SAT 解決該問題。 不難發現,使用 2-SAT 解決該問題的複雜度瓶

~ P2604 [ZJOI2010] ~ 網路擴容 小費用大流

第一問:建邊u->v容量為題中容量,花費為0,跑費用流得到的最大流就是答案。 第二問:建邊u->v容量為INF,花費題中花費,跑費用流得到的費用就是答案。 #include<bits/stdc++.h> using namespace std

P2754】 [CTSC1999]家園大流

題目連結 突然發現Dinic很好寫誒。。 第一次陣列開小了,玄學\(WA\),what?資料範圍描述有誤? 分層圖,每天為一層。 把上一天的每個空間站向這一天連一條流量為inf的邊,表示可以原地不動。 把一個週期內上一天上一個和這一天這一個連一條流量為這艘太空船的容量的邊,表示去下一站。 然後每次加一天,看什

3163 CQOI2014危橋 大流

一開始想了一發費用流做法然後直接出負環了 首先,比較顯然的思路就是對於原圖中沒有限制的邊,對應的流量就是 i n

3973 TJOI2015線性代數小割+思維

size fine clas add map ont pop 獲取 矩陣乘法 感覺要做出來這個題,需要一定的線代芝士 首先,我們來觀察這個柿子。 我們將\(B\)的權值看作是收益的話,\(C\)的權值就是花費。 根據矩陣乘法的原理,只有當\(a[i]和a[j]\)都為\(1

P3348 [ZJOI2016]大森林LCT,,樹上差分

cst log 函數 默認 位置 想法 差分 truct AC 洛谷題目傳送門 思路分析 最簡單粗暴的想法,肯定是大力LCT,每個樹都來一遍link之類的操作啦(T飛就不說了) 考慮如何優化算法。如果沒有1操作,肯定每個樹都長一樣。有了1操作,就來仔細分析一下對不同樹的影響

P1022計算器的改良字符串+各種細節坑考慮

思路 with 運算 sync ret 題意 bsp lag style 題目鏈接:https://www.luogu.org/problemnew/show/P1022 分析和思路: 題意好理解,就是字符串處理+方程求解,但是真的有很多坑點要考慮到 1 #inc

P2865 [USACO06NOV]路障Roadblocks短路

題目描述 貝茜把家搬到了一個小農場,但她常常回到FJ的農場去拜訪她的朋友。貝茜很喜歡路邊的風景,不想那麼快地結束她的旅途,於是她每次回農場,都會選擇第二短的路徑,而不象我們所習慣的那樣,選擇最短路。 貝茜所在的鄉村有RRR(1&lt;=R&lt;

BZOJ 3218 A+B Problem大流 + 主席優化

分享 bzoj post 感覺 線段樹 不能 line 需要 clas 題目:A+B Problem 感謝 Nietzsche 在省選緊迫之際花 39‘ 給我講這道題。 這題我並沒有想出來,感覺又浪費一道好題了。 需要用最小割,建模方式如下(假設若 2 取黑色,1 取白

100269D短路 spfa,權不固定的短路

傳送vj 傳送這是一個很好的  最短路的問題  。  很好。題意:  給你n  個商品 m 中換法   a,b,c  a可以用  b 或者c  來換 當然 也可以花錢買。 問你 想要得到1的最小花費。思路:  其實如果抽象一下 就是一個  邊權 可以改變的最短路問題。  既然

CF786B Legacy線段優化

好想 sin flag date ide init 技術 out nbsp 題意 有n個點,q個詢問,每次詢問有一種操作。操作1:u→[l,r](即u到l,l+1,l+2,...,r距離均為w)的距離為w;操作2:[l,r]→u的距離為w;操作3:u到v的距離為w;求起點到

【題解】[牛客網NOIP賽前集訓營-提高組第一場]C.保護 LCA+線段動態開+線段合併

題目連結 ___ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=2e5+10; int n,m,hd[N],to

【bzoj 3073】Journeys線段優化

傳送門biu~ 線段樹的每個節點代表一個區間,建兩棵線段樹。 出線段樹每個點向父節點連邊0,表示如果能從這個區間出發也就可以從父區間出發。入線段樹每個點向子節點連邊0,表示如果能到達這個區間也就可以到達子區間。 入線段樹每個點向出線段樹的平行結點連邊0,

P1886 滑動窗口POJ.2823 Sliding Window區間

最大 ide dma include names target org void blog To 洛谷.1886 滑動窗口 To POJ.2823 Sliding Window 題目描述 現在有一堆數字共N個數字(N<=10^6),以及一個大小為k的窗口。現在這個

P2057 善意的投票網絡流小割

ont c++ emp else 題意 art 自己 www. pop P2057 善意的投票 題目描述 幼兒園裏有n個小朋友打算通過投票來決定睡不睡午覺。對他們來說,這個問題並不是很重要,於是他們決定發揚謙讓精神。雖然每個人都有自己的主見,但是為了照顧一下自己朋友

題解——P1550 [USACO08OCT]打井Watering Hole小生成樹,

mount scan -o another 決定 clas con pan 通過 題面 題目背景 John的農場缺水了!!! 題目描述 Farmer John has decided to bring water to his N (1 <= N <=

P2505 [HAOI2012]道路短路計數

== true show code mes main 自己 mod target 傳送門 早上模擬賽考這題,結果竟然看錯題目了orz 然後下午看完題解自己做的時候空間開小了白WA了好久orz 首先,如果以$S$為起點,一條邊$(u,v)$在最短路上,則$dis[