hdu4601 Letter Tree,trie,bfs,dfs,二分,rmq

18 篇文章 0 订阅
10 篇文章 0 订阅
真的是很有意思的题。
因为有重复的边,我想了很多贪心搞法都错了。最后还是看了标解。
trie+bfs+dfs+二分+rmq。OMG

最重要的还是几点吧:
1.通过在trie上dfs/bfs可以知道某个节点的hash值大小,因为有mod,直接比较值是没法比较大小的。
2.bfs可以将树上同一深度的点放在一个连续区间,而dfs可以求出子树区间,结合就能找到子树中某个深度的最值。

注意m=0时输出0。

写这种很多东西结合的看起来很长的题,最好先把变量名规划好,要用的东西也在纸上标记好,这样实现起来事半功倍。
很多时候觉得手速不够,现在想来还是没想清楚,思考纠结的时间远大于敲代码的时间。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
#define NN 101100
#define mpa make_pair
#define pb push_back

const long long mod=1000000007;
const long long inf=1000000100;
const long long mag=26;

typedef pair<int,int> pii;
vector<pii> ed[NN];

int n;

int bseq[NN],bn;
int dn;
int seq[NN],tseq;
int vis[NN];
int depbeg[NN],depend[NN];
int dbeg[NN],dend[NN],dep[NN];
long long sv[NN];

int r[NN];
long long val[NN];

//trie------------------
int tott;
int root;
struct trie{
    int son[26];
    void init(){memset(son,0,sizeof(son));}
}t[NN];

void dfsbuild(int u,int f,int p,long long tv){//build trie
    r[u]=p;
    val[u]=tv;
    int v,i,id;
    int sz=ed[u].size();
    for(i=0;i<sz;++i){
        v=ed[u][i].second;
        if (v==f) continue;
        id=ed[u][i].first;
        if (t[p].son[id]) dfsbuild(v,u,t[p].son[id],(long long)(tv*mag+(long long)id)%mod);
        else {
            t[p].son[id]=++tott;
            t[tott].init();
            dfsbuild(v,u,tott,(long long)(tv*mag+(long long)id)%mod);
        }
    }
}

void dfstrie(int u){//get seq
    seq[u]=++tseq;
    int i;
    long long tmp;
    for(i=25;i>=0;--i){
        if (t[u].son[i]){
            dfstrie(t[u].son[i]);
        }
    }
}
//trie--------------------

//rmq-------------------------------------------------------
int mi[NN][18];
int mv[NN][18];

void rmqinit(int n){
    int m=-1,k=n;
    while(k) {m++;k>>=1;}
    int i,j;
    for(i=1;i<=n;i++) {mi[i][0]=seq[r[bseq[i]]];mv[i][0]=bseq[i];}
    for(i=1;i<=m;i++){
        for(j=1;j<=n;j++){
            mi[j][i]=mi[j][i-1];mv[j][i]=mv[j][i-1];
            if (j+(1<<(i-1))<=n){
                if (mi[j][i]>mi[j+(1<<(i-1))][i-1]){
                    mi[j][i]=mi[j+(1<<(i-1))][i-1];
                    mv[j][i]=mv[j+(1<<(i-1))][i-1];
                }
            }
        }
    }
}

int rmqmin(int l,int r){
    int m=-1,k=r+1-l;
    while(k) {k>>=1;m++;}
    if (mi[l][m]<mi[r+1-(1<<m)][m]) return mv[l][m];
    else return mv[r+1-(1<<m)][m];
}
//--------------------------rmq----------------------------------

void bfs(){
    queue<int> q;
    memset(vis,0,sizeof(vis));
    int u=1,i,v;
    q.push(u);
    vis[u]=1;
    bn=0;
    memset(depbeg,-1,sizeof(depbeg));
    while(!q.empty()){
        u=q.front();q.pop();
        bseq[++bn]=u;
        depend[vis[u]]=bn;
        if  (depbeg[vis[u]]==-1) {depbeg[vis[u]]=bn;}
        for(i=0;i<ed[u].size();++i){
            v=ed[u][i].second;
            if (!vis[v]){
                q.push(v);
                vis[v]=vis[u]+1;
            }
        }
    }
}

void dfs(int u,int f,int ddep){
    dep[u]=ddep;
    dbeg[u]=++dn;
    int i,v;
    for(i=0;i<ed[u].size();++i){
        v=ed[u][i].second;
        if (v==f) continue;
        dfs(v,u,ddep+1);
    }
    dend[u]=++dn;
}

void init_sv(){
    int i;
    sv[0]=1;
    for(i=1;i<=100010;++i){
        sv[i]=(sv[i-1]*mag)%mod;
    }
}

void init(int n){
    int i;
    tott=1;
    root=1;
    t[root].init();
    tseq=0;
    for(i=0;i<=n+100;++i){
        ed[i].clear();
    }
    memset(depbeg,-1,sizeof(depbeg));
}

int bsch_lower(int ll,int rr,int val){
    int m,ans=rr+1;
    while(ll<=rr){
        m=(ll+rr)/2;
        if (dbeg[bseq[m]]>val){
            if (ans>m) ans=m;
            rr=m-1;
        }
        else ll=m+1;
    }
    return ans;
}

int bsch_upper(int ll,int rr,int val){
    int m,ans=ll-1;
    while(ll<=rr){
        m=(ll+rr)/2;
        if (dbeg[bseq[m]]<val){
            if (ans<m) ans=m;
            ll=m+1;
        }
        else rr=m-1;
    }
    return ans;
}

long long work(int u,int m){
    int tmp=dep[u]+m,v;
    if (tmp>n+1||depbeg[tmp]==-1) return inf;
    int lb=bsch_lower(depbeg[tmp],depend[tmp],dbeg[u]);
    int ub=bsch_upper(depbeg[tmp],depend[tmp],dend[u]);
    if (ub>=lb){
        v=rmqmin(lb,ub);
        return (val[v]-val[u]*sv[dep[v]-dep[u]]%mod+mod)%mod;
    }
    else return inf;
}

int main(){
    //freopen("4601in.txt","r",stdin);
    int cas,i,a,b,q,u,m;
    char ts[20];
    init_sv();
    scanf("%d",&cas);
    while(cas--){
        scanf("%d",&n);
        init(n);
        for(i=1;i<n;++i){
            scanf("%d%d%s",&a,&b,ts);
            ed[a].pb(mpa(ts[0]-'a',b));
            ed[b].pb(mpa(ts[0]-'a',a));
        }
        dfsbuild(1,0,root,0);
        tseq=0;
        dfstrie(1);

        bfs();
        rmqinit(n);
        dn=0;
        dfs(1,-1,1);
        scanf("%d",&q);
        for(i=1;i<=q;++i){
            scanf("%d%d",&u,&m);
            if (u>n||u<0) {puts("IMPOSSIBLE");continue;}
            if (m==0) puts("0");
            else {
                long long tmp=work(u,m);
                if (tmp==inf) puts("IMPOSSIBLE");
                else printf("%I64d\n",tmp);
            }
        }
    }
    return 0;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值