[SDOI2017] Gifted Hacker

1. Title

Click on this topic

2. Solution

Really poisonous tumour, I have been working on TM for three hours, it's so cool to use.

Back to the point, it's easy to think of a shortest-path solution. We split each edge into two points. The edge weights between them are the original edge weights. For each point (the original image), we force the entry and exit points to connect the edges. The edge weights are lcplcplcp (the depth of lcalca in the dictionary tree_1-1_1). This gives you a high score of 1000 because of the entry point and exit point.When points are connected, the maximum number of edges is m2m^2m2, and then the time complexity is too weak to return.

Consider optimizing. The problem now is that there are too many edges. Can we reduce some?

The official solution uses this property of lca calculation whose weight is the dictionary tree. We can use the idea of a virtual tree. First we sort the entry and exit points using dfndfndfn of the dictionary tree, and then we come to a conclusion: LCP (a l, a r) =min_i=l r_1lcp (a i, a i+1) LCP (a_l, a_r) =\min_{i=i=l}^{r-1} {r-1} LCP (a_i, a_{i+1}) LCP (a l, a l ({i+1}) LCP (a l) =min I r = L r = l r_i=l r_lcp (min I lcp(a i, a i+1)

Considering that the shortest path will be chosen, we can use the adjacent lcplcplcp of dfndfn to represent the lcplcplcp of the interval, which is implemented as follows:

Assuming that we have obtained some entry and exit points (the size of this example number represents the size of dfndfn), we first connect the adjacent entry and exit points with a edge weight of 000:

We want to use the adjacent edges of dfndfn to represent all edges. The image above should be connected like this:

To summarize, first sort the adjacent points, set them as (x,y)(x,y)(x,y), find that dfndfn is less than or equal to x x x and the rightmost, dfndfn is greater than or equal to y y y's leftmost side, connect them with lcp(x,y)lcp(x,y)lcp(x,y)

The examples given above only show the way to handle small outgoing big connections. In fact, there is also a way to handle the reverse (for example, we can handle 1>21->21>2 above, but we can't handle 6>26->26>2), so we have to double this part and do it again in a similar way.

Then run directly to dijkstradijkstradijkstra (it turns out I can't write dij and can't call it up all the time), put a code with a comment.

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 20005;
const int M = 200005;
#define LL long long
#define inf (1ll<<60)
int read()
 int x=0,flag=1;char c;
 while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
 while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
 return x*flag;
int T,n,m,k,Index,tot,id,t,f[M],tmp[M],pos[M],dfn[N],dep[N],fa[N][20];
vector<int> rr[M],cc[M],g[M];LL dp[M];
struct edge
 int v,c,next;
 edge(int V=0,int C=0,int N=0) : v(V) , c(C) , next(N) {}
struct node
    int u;LL c;
    node(int U=0,LL C=0) : u(U) , c(C) {}
    bool operator < (const node &B) const
        return c>B.c;
void add(int u,int v,int c)
void ins(int u,int v,int c,int d)
{//Two parts, to split into four points, 13 out, 24 in
int Abs(int x)
    return x>0?x:-x;
bool cmp(int a,int b)
{//dfn sort, abs added because negative numbers are marked below
    return dfn[pos[Abs(a)]]<dfn[pos[Abs(b)]];
void dfs(int u,int p)//Preprocessing of Dictionary Tree
 for(int i=1;i<20;i++)
 for(int i=0;i<g[u].size();i++)
int lca(int u,int v)
 if(dep[u]<=dep[v]) swap(u,v);
 for(int i=19;i>=0;i--)
 if(u==v) return u;
 for(int i=19;i>=0;i--)
 return fa[u][0];
int get(int u,int v)//lcp
 return dep[lca(u,v)]-1;
void build(int x)
 if(rr[x].empty() || cc[x].empty()) return ;
 int len=0,tt;
 for(int i=rr[x].size()-1;i>0;i--) add(rr[x][i-1]*4-2,rr[x][i]*4-2,0),add(rr[x][i]*4,rr[x][i-1]*4,0);//Adjacent Join
 for(int i=cc[x].size()-1;i>0;i--) add(cc[x][i-1]*4-3,cc[x][i]*4-3,0),add(cc[x][i]*4-1,cc[x][i-1]*4-1,0);
 for(int i=0;i<cc[x].size();i++) tmp[++len]=-cc[x][i];//Save and sort, mark with negative numbers
 for(int i=0;i<rr[x].size();i++) tmp[++len]=rr[x][i];
 for(int t=1,i=0,j=0;t<len;t++)
        if(tmp[t]<0) j++,tmp[t]*=-1;else i++;//Move subscripts with typed markers (i is in, j is out, not reached)
        if(i!=0 && j!=cc[x].size()) add(rr[x][i-1]*4-2,cc[x][j]*4-3,tt);//Divide into two parts
        if(j!=0 && i!=rr[x].size()) add(rr[x][i]*4,cc[x][j-1]*4-1,tt);
void dijkstra()
    priority_queue<node> q;
    t++;//Create one more starting point, all starting points of 1
    for(int i=cc[1].size()-1;i>=0;i--) add(t,cc[1][i]*4-3,0),add(t,cc[1][i]*4-1,0);//There was no equal sign at first.
    memset(dp,0x3f,sizeof dp);
        node t=q.top();q.pop();
        if(t.c>dp[t.u]) continue ;
        for(int i=f[t.u];i;i=e[i].next)
            int v=e[i].v,c=e[i].c;
                q.push(node(v,dp[v]));//It's written as c here, and it's got 25 more points, and the sample hasn't been stuck yet.
    for(int i=2;i<=n;i++)
        LL ans=inf;
        for(int j=0;j<rr[i].size();j++)
int main()
  memset(f,0,sizeof f);
  for(int i=1;i<=k;i++) g[i].clear();
  for(int i=1;i<=n;i++) rr[i].clear(),cc[i].clear();
  for(int i=1;i<=m;i++)
   int u=read(),v=read(),c=read(),d=read();
  for(int i=1;i<k;i++)
            int u=read(),v=read();read();
        for(int i=2;i<=n;i++)
            build(i);//You don't need to build 1, because 1 starts straight away and its string is the best
192 original articles published, 12 praised, 3209 visits
Private letter follow

Tags: less

Posted on Sat, 11 Jan 2020 22:09:35 -0500 by mitcho