[模板] 点分治
Posted dukelv
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[模板] 点分治相关的知识,希望对你有一定的参考价值。
之前搞了一个树的中心,结果当时把点分治给扔下了,现在搞一搞。其实点分治的分治思想很明显,就是把树切成一个个小树,然后在重心的位置再分治就行了。
代码实现有一定困难,但就我觉得前一个函数和树刨的dfs1很像吗,详情见代码。
题干:
题目背景 感谢hzwer的点分治互测。 题目描述 给定一棵有n个点的树 询问树上距离为k的点对是否存在。 输入输出格式 输入格式: n,m 接下来n-1条边a,b,c描述a到b有一条长度为c的路径 接下来m行每行询问一个K 输出格式: 对于每个K每行输出一个答案,存在输出“AYE”,否则输出”NAY”(不包含引号) 输入输出样例 输入样例#1: 复制 2 1 1 2 2 2 输出样例#1: 复制 AYE 说明 对于30%的数据n<=100 对于60%的数据n<=1000,m<=50 对于100%的数据n<=10000,m<=100,c<=1000,K<=10000000
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < ‘0‘ || c > ‘9‘) if(c == ‘-‘) op = 1; x = c - ‘0‘; while(c = getchar(), c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar(‘-‘), x = -x; if(x >= 10) write(x / 10); putchar(‘0‘ + x % 10); } struct node { int l,r,nxt,w; } a[40005]; int lst[40005],len = 0,n,m; void add(int x,int y,int w) { a[++len].l = x; a[len].r = y; a[len].w = w; a[len].nxt = lst[x]; lst[x] = len; } int qu[405],maxp[40005],sum,rt = 0,siz[40005]; int vis[40005],judge[10000000],test[10000000]; int q[40005],dis[40005],rem[40005]; void getrt(int u,int pa) { siz[u] = 1; maxp[u] = 0; for(int k = lst[u]; k; k = a[k].nxt) { int y = a[k].r; if(y == pa || vis[y]) continue; getrt(y,u); siz[u] += siz[y]; maxp[u] = max(maxp[u],siz[y]); } maxp[u] = max(maxp[u],sum - siz[u]); if(maxp[u] < maxp[rt]) rt = u; } void getdis(int u,int fa) { rem[++rem[0]] = dis[u];//主要是这一句,就是rem中存了所有可能的长度 for(int k = lst[u]; k; k = a[k].nxt) { int y = a[k].r; if(y == fa || vis[y] == 1) continue; dis[y] = dis[u] + a[k].w;//记录子树中的距离 getdis(y,u); } } void calc(int u) { int p = 0; for(int k = lst[u]; k; k = a[k].nxt) { int y = a[k].r; if(vis[y] == 1) continue; rem[0] = 0; dis[y] = a[k].w; getdis(y,u); lv(j,rem[0],1) { duke(i,1,m) { if(qu[i] >= rem[j]) test[i] |= judge[qu[i] - rem[j]];//尝试匹配 } } lv(j,rem[0],1) { q[++p] = rem[j];//就是一个过程量 judge[rem[j]] = 1; } } duke(i,1,p) judge[q[i]] = 0;//清空当前子树judge数组 } void solve(int u) { vis[u] = judge[0] = 1; calc(u); for(int k = lst[u]; k; k = a[k].nxt) { int y = a[k].r; if(vis[y]) continue; sum = siz[y]; maxp[rt = 0] = INF; getrt(y,0); solve(rt); } } int main() { read(n); read(m); duke(i,1,n - 1) { int x,y,w; read(x); read(y); read(w); add(x,y,w); add(y,x,w); } duke(i,1,m) read(qu[i]); maxp[rt] = sum = n; getrt(1,0); // cout<<"QAQ"<<endl; solve(rt); duke(i,1,m) { if(test[i]) printf("AYE "); else printf("NAY "); } return 0; }
以上是关于[模板] 点分治的主要内容,如果未能解决你的问题,请参考以下文章