GRE Words

这道题不难想到这样的dp。

dp[字符串si] = 以si为结尾的最大总权值。

dp[si] = max(dp[sj]) ,1.j < i,2.sj是si的子串。

对于第二个条件,是一个多模版串匹配的问题,可以用AC自动机。

预先O(m)把AC自动机建好,然后动态更新AC自动机上的dp值,

匹配的时候,指向字符的指针移动总共是O(m),

而每个单词,fail指针走寻找后缀却是O(m),即使改成后缀链接也是O(n)。too slow!

找到一个单词后,需要避免找后缀,动态维护这个单词的dp值。

一开始所有单词的dp都是0。

更新的时候,dp[si]需要更新所有dp[sj],其中si是sj的后缀。

如果父节点是子节点的后缀,把所有的单词(包括空后缀)连接起来将会得到以空字符串为根的后缀链接树。

这样就变成一个更新子树的问题,dfs把树形转成线性以后可以用线段树来维护。

询问单点最大值,区间更新O(logn)。

复杂度O(mlogn)

潜在的坑点:

1.Trie个结点可能对应多个单词,如果只更新了其中一个单词的线性区间RE...(map,前向链表,vector都可以搞

/*********************************************************
*            ------------------                          *
*   author AbyssFish                                     *
**********************************************************/
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;

const int LEN = 3e5+5;
const int MAXN = 2e4+5;

int W[MAXN], S[MAXN];
int N;
char s[LEN];

int hd[LEN];
int nx[MAXN], to[MAXN], ec;

void add_e(int u,int v)
{
    to[ec] = v;
    nx[ec] = hd[u];
    hd[u] = ec++;
}
#define eachedge int i = hd[u]; ~i; i = nx[i]
inline void init_g(int n){ memset(hd,-1,n<<2); ec = 0; }
int L[MAXN], R[MAXN], dfs_clk; //string‘s linear suffix link tree id
const int ST_SIZE = 1<<16;
int dp[ST_SIZE];

#define para int o = 1,int l = 0,int r = dfs_clk
#define lo (o<<1)
#define ro (o<<1|1)
#define Tvar int md = (l+r)>>1;
#define lsn lo,l,md
#define rsn ro,md,r
#define insd ql<=l&&r<=qr

void build(para)
{
    dp[o] = 0;
    if(r-l>1){
        Tvar
        build(lsn);
        build(rsn);
    }
}

void update(int ql,int qr,int v,para)
{
    if(insd){
        dp[o] = max(dp[o],v);
    }
    else {
        Tvar
        if(ql < md) update(ql,qr,v,lsn);
        if(qr > md) update(ql,qr,v,rsn);
    }
}

int query(int p,para)
{
    int re = 0;
    while(r-l>1){
        Tvar
        if(p<md){
            o = lo; r = md;
        }
        else {
            o = ro; l = md;
        }
        re = max(re,dp[o]);
    }
    return re;
}

const int sigma_size = 26, MAXND = LEN;
struct AhoCorasick_automata
{
    #define idx(x) (x-‘a‘)
    int ch[MAXND][sigma_size];

    int f[MAXND];
    int last[MAXND];
    int cnt;

    int val[MAXND];
    int nx_val[MAXN];
    void add_v(int o,int x)
    {
        nx_val[x] = val[o];
        val[o] = x;
    }

    int newNode()
    {
        int i = ++cnt;
        memset(ch[i],0,sizeof(ch[i]));
        val[i] = 0;
        return i;
    }

    void init()
    {
        cnt = -1; newNode();
    }

    int add(char *s,int id)
    {
        int u = 0, i, c;
        for(i = 0; s[i]; i++){
            c = idx(s[i]);
            if(!ch[u][c]){
                ch[u][c] = newNode();
            }
            u = ch[u][c];
        }
        add_v(u,id);
        return i;
    }

    queue<int> q;
    void getFail()
    {
        int u, c, v, r;
        //f[0] = 0; last[0] = 0;
        for(c = 0; c < sigma_size; c++){
            u = ch[0][c];
            if(u){
                q.push(u);
                f[u] = 0;
                last[u] = 0;
            }
        }
        while(!q.empty()){
            r = q.front(); q.pop();
            for(c = 0; c < sigma_size; c++){
                u = ch[r][c];
                if(u){
                    q.push(u);
                    v = f[u] = ch[f[r]][c];
                    last[u] = val[v] ? v : last[v];
                }
                else ch[r][c] = ch[f[r]][c];
            }
        }
    }

    void dfs(int u)
    {
        int le = dfs_clk++;
        for(eachedge){
            dfs(to[i]);
        }
        int ri = dfs_clk;
        for(int id = val[u]; id; id = nx_val[id]){
            L[id] = le; R[id] = ri;
        }
    }

    void buildTree()
    {
        init_g(cnt+1);
        for(int u = 1; u <= cnt; u++)if(val[u]){
            add_e(last[u],u);
        }
        dfs_clk = 0;
        dfs(0);
    }

    void work()
    {
        int i,j,c,u,id;
        int ans = 0, mx;
        build();
        for(i = 1; i <= N; i++){
            u = 0; mx = 0;
            for(j = S[i-1]; j < S[i]; j++){
                c = idx(s[j]);
                u = ch[u][c];
                if(val[u]){
                    id = val[u];
                    mx = max(mx, query(L[id]));
                }
                else if(last[u]){
                    id = val[last[u]];
                    mx = max(mx, query(L[id]));
                }
            }
            if(W[i] > 0){
                ans = max(ans, mx += W[i]);
                update(L[i],R[i],mx);
            }
        }
        printf("%d\n",ans);
    }

}ac;

void solve()
{
    scanf("%d",&N);
    ac.init();
    for(int i = 1; i <= N; i++){
        scanf("%s%d",s+S[i-1],W+i);
        S[i] = ac.add(s+S[i-1],i)+S[i-1];
    }
    ac.getFail();
    ac.buildTree();
    ac.work();
}

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("data.txt","r",stdin);
#endif
    int T, kas = 0; scanf("%d",&T);
    while(++kas <= T){
        printf("Case #%d: ",kas);
        solve();
    }
    return 0;
}
时间: 2024-08-11 05:36:42

GRE Words的相关文章

【DCN】Gre over ipsec vpn

流量被加密的过程: 首先数据包进入路由器,路由器查询路由表,进入Tu0,数据被GRE封包,再次查询路由表,到物理接口,触发加密图,数据加密,再送出路由器. GRE OVER  IPSEC VPN 的出现解决了IPSEC VPN不能加密组播及广播报文的问题使得IPSEC VPN不能在动态路由协议中得到应用,而使用GRE OVER IPSEC VPN的好处就是GRE能够很好的封闭组播及广播流量,再被IPSEC VPN加密传输使得这一方案得到广泛应用. GRE OVER IPSEC VPN 的ACL表

hdu 4787 GRE Words Revenge 在线AC自动机

hdu 4787 GRE Words Revenge Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)Total Submission(s): 2505    Accepted Submission(s): 614 Problem Description Now Coach Pang is preparing for the Graduate Record Examina

gre网络细节

一.OpenStack网络设备的命名规律: 1.TenantA的router和Linux网络命名空间qrouter名称 [email protected]:~# neutron --os-tenant-name TenantA --os-username UserA --os-password password --os-auth-url=http://localhost:5000/v2.0 router-list --field id --field name +---------------

网络叠加模式VLAN、VxLAN、GRE

什么是叠加网络 1.一个数据包(或帧)封装在另一个数据包内;被封装的包转发到隧道端点后再被拆装. 2.叠加网络就是使用这种所谓"包内之包"的技术安全地将一个网络隐藏在另一个 网络中,然后将网络区段进行迁移. 一.VLAN介绍 VLAN,是英文Virtual Local Area Network的缩写,中文名为"虚拟局域网", VLAN是 一种将局域网(LAN)设备从逻辑上划分(注意,不是从物理上划分)成一个个网段(或者 说是更小的局域网LAN),从而实现虚拟工作组(

综合(奇技淫巧):HDU 5118 GRE Words Once More!

GRE Words Once More! Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others)Total Submission(s): 205    Accepted Submission(s): 32 Problem Description Now Matt is preparing for the Graduate Record Examinations as Coach P

Linux下的GRE隧道及其路由转发

隧道,字面上来看就是一条通道,这条通道由点到点,独立与其他.linux下的隧道其他的了解不深,单独写下最近搭建过的gre隧道和路由转发功能实现. 先说一下隧道的基本概念: 一种技术(协议)或者策略的两个或多个子网穿过另一种技术(协议)或者策略的网络实现互联,称之为overlay topology,这一技术是电信技术的永恒主题之一.     电信技术在发展,多种网络技术并存,一种技术的网络孤岛可能需要穿过另一种技术的网络实现互联,这种情况如果发生在高层协议的PDU封装于低层协议PDU中时通常称之为

玩转OpenStack网络Neutron(4)--网络隧道技术 VXALN &amp; GRE

欢迎转载,转载请保留原作者信息 欢迎交流学习,共同进步! 作者:颜海峰 个人博客:http://yanheven.github.io 微博:海峰_云计算 http://weibo.com/344736086 网络隧道技术介绍 计算节点配置 Open vSwitch 使用 VXLAN 网络 网络节点配置 Open vSwitch 使用 VXLAN 网络 配置 Neutron 使用 VXLAN Type Driver 配置 VXLAN 编号范围 查看 Neutron 网络的 VNI 指定 VNI 创

[转]两台linux建立GRE隧道

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://333234.blog.51cto.com/323234/931805 1.拓扑图: 备注:因为应用原因,需要在linux2上添加一个公网地址,并且在中间路由设备不受控制的情况下,Linux1能访问到linux2上面的公网地址. 2.基本接口配置: linux1:192.168.10.1/24 linux2:192.168.20.2/24 R1: interface FastEt

[转]在openvswitch上配置GRE tunnel

Posted in Linux Application at November 13th, 2012 如果你是用 openvswitch 内置的 GRE tunnel,那么配置很简单,基本上就一条命令: ovs-vsctl add-port br0 gre0 -- set interface gre0 type=gre options:remote_ip=192.168.1.10 本文想谈的显然不是这个.因为 upstream 内核(指 Linus tree)中的 openvswitch 是不支

[转]深入理解GRE tunnel

Posted in Linux Kernel at November 8th, 2012 / 1 Comment ? 我以前写过一篇介绍 tunnel 的文章,只是做了大体的介绍.里面多数 tunnel 是很容易理解的,因为它们多是一对一的,换句话说,是直接从一端到另一端.比如 IPv6 over IPv4 的 tunnel,也就是 SIT,它的原理如下图所示: 显然,除了端点的 host A 和 host B之外,中间经过的任何设备都是看不到里面的 IPv6 的头,对于它们来说,经过 sit