Live2d Test Env

Gym - 100962F: Frank Sinatra (树上莫队+bitset)

题意:给定一棵树,带边权。然后Q次询问,每次给出(u,v),求这个路径上最小的未出现的边权。

思路:树上莫队,求mex可以用分块或者bitset,前者可能会快一点。   莫队过程:求出欧拉序,即记录dfs的in和out时间戳。 然后摊平成数组,在数组上进行莫队。

一般的莫队需要单独考虑LCA,因为LCA不在这个区间里。 但是由于这里是边权,用儿子代替边权,所以LCA本来就不用考虑。

这个序列里,有效的部分是出现奇数次的,所以用vis记录奇偶性,如果是奇,表示加; 偶表示删。 

如果想再快一点,可以把bitset改为分块; 以及,用王室联邦分块法(即后序遍历,这样可以保证一个块更近一些)。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=1000010;
bitset<maxn>S; int num[maxn],val[maxn],ans[maxn];
int Laxt[maxn],Next[maxn],To[maxn],len[maxn],cnt;
int p[maxn],L[maxn],R[maxn],times,B,N,Q,vis[maxn];
struct in{
    int l,r,id;
    bool friend operator <(in w,in v){
        if(w.l/B!=v.l/B) return w.l<v.l;
        return w.r<v.r;
    }
}s[maxn];
void add(int u,int v,int w)
{
    Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; len[cnt]=w;
}
void dfs(int u,int f)
{
    p[++times]=u; L[u]=times;
    for(int i=Laxt[u];i;i=Next[i]){
        int v=To[i]; if(v==f) continue;
        val[v]=len[i]; dfs(v,u);
    }
    p[++times]=u; R[u]=times;
}
void fcy(int pos)
{
    pos=p[pos];
    if(val[pos]>N) return ;
    vis[pos]^=1;
    if(vis[pos]) {
        num[val[pos]]++;
        if(num[val[pos]]==1) S[val[pos]]=0;
    }
    else {
        num[val[pos]]--;
        if(num[val[pos]]==0) S[val[pos]]=1;
    }
}
void solve()
{
    sort(s+1,s+Q+1);
    int l=s[1].l,r=s[1].l-1;
    rep(i,1,Q){
        while(l<s[i].l) fcy(l++);
        while(l>s[i].l) fcy(--l);
        while(r<s[i].r) fcy(++r);
        while(r>s[i].r) fcy(r--);
        ans[s[i].id]=S._Find_first();
    }
}
int main()
{
    int u,v,w;
    S.set(); //没出现的就是1
    scanf("%d%d",&N,&Q);
    B=(int)sqrt(N+N);
    rep(i,1,N-1){
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    dfs(1,0); val[1]=N+1;
    rep(i,1,Q) {
        scanf("%d%d",&u,&v);
        if(L[u]>L[v]) swap(u,v);
        s[i].l=R[u]; s[i].r=L[v]; s[i].id=i;
    }
    solve();
    rep(i,1,Q) printf("%d\n",ans[i]);
    return 0;
}

 

王室联邦写法: 但跑出来这个更慢?

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=1000010;
bitset<maxn>S; int num[maxn],val[maxn],ans[maxn];
int Laxt[maxn],Next[maxn],To[maxn],len[maxn],cnt;
int p[maxn],L[maxn],R[maxn],times,B,N,Q,vis[maxn];
int q[maxn],top,g[maxn],group;
struct in{
    int l,r,id;
    bool friend operator <(in w,in v){
        if(g[p[w.l]]!=g[p[v.l]]) return g[p[w.l]]<g[p[v.l]];
        return g[p[w.r]]<g[p[v.r]];
    }
}s[maxn];
void add(int u,int v,int w)
{
    Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; len[cnt]=w;
}
void dfs(int u,int f)
{

    p[++times]=u; L[u]=times;
    int now=top;
    for(int i=Laxt[u];i;i=Next[i]){
        int v=To[i]; if(v==f) continue;
        val[v]=len[i]; dfs(v,u);
        if(top-now>=B){
            group++;
            while(top!=now) g[q[top--]]=group;
        }
    }
    q[++top]=u;
    p[++times]=u; R[u]=times;
}
void fcy(int pos)
{
    pos=p[pos];
    if(val[pos]>N) return ;
    vis[pos]^=1;
    if(vis[pos]) {
        num[val[pos]]++;
        if(num[val[pos]]==1) S[val[pos]]=0;
    }
    else {
        num[val[pos]]--;
        if(num[val[pos]]==0) S[val[pos]]=1;
    }
}
void solve()
{
    sort(s+1,s+Q+1);
    int l=s[1].l,r=s[1].l-1;
    rep(i,1,Q){
        while(l<s[i].l) fcy(l++);
        while(l>s[i].l) fcy(--l);
        while(r<s[i].r) fcy(++r);
        while(r>s[i].r) fcy(r--);
        ans[s[i].id]=S._Find_first();
    }
}
int main()
{
    int u,v,w;
    S.set(); //没出现的就是1
    scanf("%d%d",&N,&Q);
    B=(int)sqrt(N+N);
    rep(i,1,N-1){
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    dfs(1,0); val[1]=N+1;
    while(top) g[q[top--]]=group;
    rep(i,1,Q) {
        scanf("%d%d",&u,&v);
        if(L[u]>L[v]) swap(u,v);
        s[i].l=R[u]; s[i].r=L[v]; s[i].id=i;
    }
    solve();
    rep(i,1,Q) printf("%d\n",ans[i]);
    return 0;
}

 

posted @ 2019-08-24 18:03  nimphy  阅读(333)  评论(0编辑  收藏  举报