题解:luoguP3806 【模板】点分治1(在线处理询问做法)
题目描述
给定一棵有n个点的树
询问树上距离为k的点对是否存在。
输入输出格式
输入格式:
n,m 接下来n-1条边a,b,c描述a到b有一条长度为c的路径
接下来m行每行询问一个K
输出格式:
对于每个K每行输出一个答案,存在输出“AYE”,否则输出”NAY”(不包含引号)
输入输出样例
说明
对于30%的数据n<=100
对于60%的数据n<=1000,m<=50
对于100%的数据n<=10000,m<=100,c<=1000,K<=10000000
题解:
这题数据是真的水,交时以为要T,结果过了......
直接套点分治板子,暴力在线处理每个询问,可以水过
当处理完与i相关的每条路径后,直接两两组合,排序后直接分别求出大于等于k和小于等于k的路径数后,再将其相加并减去总的路径组合数,就是等于k的路径组合。处理每层的复杂度大致是O(n+nlogn)
详情见代码:
#include<bits/stdc++.h> #define MAXN 10005 #define INF 1e9+7 using namespace std; struct front_star{ int to,next,w; }edge[MAXN<<1]; int n,cnt=0,k,mx,root,ans=0,tot=1,siz,m; int head[MAXN],sz[MAXN],temp[MAXN],idx[MAXN]; bool vis[MAXN]; int maxn(int a,int b) { return a>b?a:b; } void addedge(int u,int v,int c) { cnt++; edge[cnt].to=v; edge[cnt].w=c; edge[cnt].next=head[u]; head[u]=cnt; } void findroot(int u,int fa) { sz[u]=1; int msz=0; for(int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if(v!=fa&&!vis[v]) { findroot(v,u); sz[u]+=sz[v]; msz=maxn(msz,sz[v]); } } msz=maxn(msz,siz-sz[u]); if(msz<mx) { mx=msz; root=u; } } void init() { memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(int i=1;i<=n-1;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); addedge(a,b,c); addedge(b,a,c); } } void dist(int u,int fa) { for(int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if(!vis[v]&&v!=fa) { tot++; idx[v]=tot; temp[tot]=temp[idx[u]]+edge[i].w; dist(v,u); } } } int count_ans(int u,int val) { tot=1; idx[u]=1; temp[1]=val; dist(u,u); sort(temp+1,temp+1+tot); int L=1,R=tot,res1=0,res2=0,ret; while(L<=R) { if(temp[L]+temp[R]<=k) { res1+=R-L; L++; } else R--; } L=1,R=tot; while(L<=R) { if(temp[L]+temp[R]>=k) { res2+=R-L; R--; } else L++; } ret=res1+res2-(tot*(tot-1))/2; return ret; } void divide(int u) { ans+=count_ans(u,0); vis[u]=true; for(int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if(!vis[v]&&!vis[v]) { ans-=count_ans(v,edge[i].w); siz=sz[v]; mx=INF; findroot(v,u); divide(root); } } } void query() { for(int i=1;i<=m;i++) { memset(vis,false,sizeof(vis)); scanf("%d",&k); siz=n; mx=INF; ans=0; findroot(1,1); divide(root); if(ans==0) printf("NAY\n"); else printf("AYE\n"); } } int main() { init(); query(); return 0; }
小鳥の翼がついに大きくなって ,
旅立ちの日だよ ,
遠くへと広がる海の色暖かく ,
夢の中で描いた絵のようなんだ ,
切なくて時をまきもどしてみるかい ?
No no no いまが最高!
だってだって、いまが最高!