GYM 100962F Problem F. Frank Sinatra(树上莫队+分块)

来源:互联网 发布:3dmax软件 编辑:程序博客网 时间:2024/06/05 22:31

题目链接

Problem F. Frank Sinatra

分析

这题和前面那个题唯一不一样的地方是,这题访问的是边上的,因此可以将边上的值算做入边顶点的值,这样就 u,v 对应的区间就是 [dfl[u]+1,dfl[v]], 这样开个桶记录访问到的数就行了.

code

#include <bits/stdc++.h>using namespace std;#define ms(x,v) (memset((x),(v),sizeof(x)))#define pb push_back#define mp make_pair#define fi first#define se secondtypedef long long LL;typedef pair<int,int > Pair;const int maxn = 1e5+10;int n,m;const int S = 320;struct Query{    int id,l,r,backet;    bool operator<(const Query & o)const{        return backet==o.backet?(backet&1?r>o.r : r <o.r) : l<o.l;    }} q[maxn];std::vector<Pair> G[maxn];int dfl[maxn],dfr[maxn],dfn[maxn<<1],val[maxn],dft=0;int cnt[maxn],vis[maxn],sum[maxn],ret[maxn];void dfs(int x) {    dfl[x] = ++dft;dfn[dft] = x;    for(auto v : G[x])        if(!dfl[v.fi])val[v.fi] =v.se, dfs(v.fi);    dfr[x] = ++dft;dfn[dft] = x;}inline void move(int node) {    if(val[node]>n)return;    if(vis[node] && --cnt[val[node]]==0)--sum[val[node]/S];    else if(!vis[node] && ++cnt[val[node]]==1)++sum[val[node]/S];    vis[node] ^=1;}inline void mo(/* arguments */) {    int l=  q[0].l,r = q[0].l-1,L,R;    for(int i=0 ;i<m ; ++i){        L = q[i].l,R = q[i].r;        while (l > L)move(dfn[--l]);        while (r < R)move(dfn[++r]);        while (l < L)move(dfn[l++]);        while (r > R)move(dfn[r--]);        int j;        for( j=0;sum[j]==S ; ++j);        for(j*=S ; cnt[j]; ++j);        ret[q[i].id]  = j;    }}int main(int argc, char const *argv[]) {    scanf("%d%d",&n,&m );    for(int i=1 ; i<n ; ++i){        int u,v,c;        scanf("%d%d%d",&u,&v,&c );        G[u].pb(mp(v,c));G[v].pb(mp(u,c));    }    dfs(1);    for(int i=0 ; i<m ; ++i){        int u,v;        scanf("%d%d",&u,&v );        if(dfl[u]> dfl[v])swap(u,v);        q[i].id = i;        q[i].l= dfl[u]+1;q[i].r = dfl[v];q[i].backet = q[i].l/S;    }    sort(q,q+m);    mo();    for(int i=0 ; i<m ; ++i)printf("%d\n",ret[i]);    return 0;}