您的位置:首页 > 其它

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

2017-11-09 20:11 351 查看

题目链接

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 second
typedef 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;

4000
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  树上莫队 分块