码迷,mamicode.com
首页 > 其他好文 > 详细

旅行路线

时间:2017-10-03 12:01:53      阅读:140      评论:0      收藏:0      [点我收藏+]

标签:不同   编号   ++   子串   scan   通过   set   use   fine   

旅行路线

时间限制: 1 Sec  内存限制: 128 MB

题目描述

A 君准备在 Z 国进行一次旅行。Z 国中有 n 个城市,城市从1到 n 进行编号,其中1号城市为 Z 国首都。Z 国的旅行交通网由 n−1条单向道路构成,并且从任何一个城市出发都可以通过旅行网到达首都。

一条旅行交通网中的旅行路线,可以用路线上所经过的城市来描述,如 {v1,v2,...,vm},它表示一条经过了m个城市的旅行路线,且城市 vi到城市 vi+1有一条单向道路相连。

若两个城市所连接的道路数量相同,则 A 君会认为这两座城市是相似的。

对于两条路线 {u1,u2,...,up}与 {v1,v2,...,vq},若 p=q且 ∀1≤i≤p,城市 ui与 vi是相似的,则 A 君认为这两条旅行路线也是相似的。 现在 A 君想知道共有多少种不同的旅行路线,相似的若干条旅行路线只算做一种。

输入

第一行一个整数n表示 Z 国城市个数。 接下来n−1行每行两个整数 x,y,表示一条从x到y的单向道路。(1≤n≤105)

输出

仅一行一个整数表示答案。

样例输入

3
2 1
3 1

样例输出

3
分析:在树上建立后缀自动机求不同子串个数;
   因为树是以1为根的有向树,直接以1为根dfs即可;
   每个点度数不定,注意儿子节点需要动态开;
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <bitset>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <cassert>
#include <ctime>
#define rep(i,m,n) for(i=m;i<=(int)n;i++)
#define inf 0x3f3f3f3f
#define mod 1000000007
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
#define pi acos(-1.0)
#define pii pair<int,int>
#define sys system("pause")
#define ls (rt<<1)
#define rs (rt<<1|1)
#define all(x) x.begin(),x.end()
const int maxn=2e5+10;
const int N=5e4+10;
using namespace std;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qmul(ll p,ll q,ll mo){ll f=0;while(q){if(q&1)f=(f+p)%mo;p=(p+p)%mo;q>>=1;}return f;}
ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p;p=p*p;q>>=1;}return f;}
int n,m,k,t;
struct samnode{
    map<int,int>son;
    int f,l;
}sam[maxn];
int cnt,root,last;
void init(){
    root = last = cnt = 1;
}
void add(int x,int last) {
    int cur = ++cnt;
    sam[cur].l = sam[last].l + 1;
    int p;
    for (p=last; p && !sam[p].son.count(x); p=sam[p].f)
        sam[p].son[x] = cur;
    if (!p)
        sam[cur].f = root;
    else {
        int q = sam[p].son[x];
        if (sam[p].l + 1 == sam[q].l)sam[cur].f = q;
        else {
            int clone = ++cnt;
            sam[clone]=sam[q];
            sam[clone].l = sam[p].l + 1;
            sam[q].f = sam[cur].f = clone;
            for (; p!=-1 && sam[p].son.count(x)&&sam[p].son[x]==q; p=sam[p].f)
            sam[p].son[x] = clone;
        }
    }
    last = cur;
}
vi e[maxn];
int du[maxn];
void dfs(int x,int rt)
{
    int i;
    add(du[x],rt);
    rt=sam[rt].son[du[x]];
    rep(i,0,e[x].size()-1)
    {
        dfs(e[x][i],rt);
    }
}
int main(){
    int i,j;
    init();
    scanf("%d",&n);
    rep(i,1,n-1)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        e[y].pb(x);
        du[x]++,du[y]++;
    }
    dfs(1,1);
    ll ret=0;
    rep(i,1,cnt)ret+=sam[i].l-sam[sam[i].f].l;
    printf("%lld\n",ret);
    return 0;
}

旅行路线

标签:不同   编号   ++   子串   scan   通过   set   use   fine   

原文地址:http://www.cnblogs.com/dyzll/p/7623406.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!