[bzoj1316] 树上的询问

  裸的点分治。。

  及时把已经确定的询问清掉就能快不少。时间复杂度O(nlogn*p)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=10023;
 7 struct zs{int len,id;bool done;}q[103];
 8 struct zs1{int too,pre,dis;}e[maxn<<1];int tot,last[maxn];
 9 int st[maxn],top,pre,sz[maxn],mx[maxn],POI,dis[maxn];
10 bool gg[103],can[1000023],del[maxn];
11 int i,j,k,n,m,rt,mm;
12
13 int ra;char rx;
14 inline int read(){
15     rx=getchar(),ra=0;
16     while(rx<‘0‘||rx>‘9‘)rx=getchar();
17     while(rx>=‘0‘&&rx<=‘9‘)ra*=10,ra+=rx-48,rx=getchar();return ra;
18 }
19 inline int max(int a,int b){return a>b?a:b;}
20 void getrt(int x,int fa){
21     sz[x]=1,mx[x]=0;
22     for(int i=last[x];i;i=e[i].pre)if(!del[e[i].too]&&e[i].too!=fa)
23         getrt(e[i].too,x),sz[x]+=sz[e[i].too],mx[x]=max(mx[x],sz[e[i].too]);
24     mx[x]=max(mx[x],POI-sz[x]);
25     if(mx[x]<mx[rt])rt=x;
26 }
27 void getpoi(int x,int fa){
28     st[++top]=dis[x];
29     for(int i=last[x];i;i=e[i].pre)if(!del[e[i].too]&&e[i].too!=fa)
30         dis[e[i].too]=dis[x]+e[i].dis,getpoi(e[i].too,x);
31 }
32 inline void updQ(){
33     mm=m;m=0;
34     for(int i=1;i<=mm;i++)if(!q[i].done)q[++m]=q[i];
35 }
36 void work(int x){
37     int i,j,k;bool flag=0;
38     rt=0,getrt(x,0);
39     can[0]=1;pre=1;
40     for(i=last[rt];i;i=e[i].pre)if(!del[e[i].too]){
41         dis[e[i].too]=e[i].dis,getpoi(e[i].too,rt);
42         for(j=pre;j<=top;j++)
43             for(k=1;k<=m&&q[k].len>=st[j];k++)if(can[q[k].len-st[j]])q[k].done=1,flag=1;
44         while(pre<=top)
45             if(st[pre]<=q[1].len)
46                 can[st[pre++]]=1;
47             else pre++;
48     }
49     if(flag)updQ();
50     if(!m)return;
51     while(top)
52         if(st[top]<=1000000)can[st[top--]]=0;else top--;
53     del[rt]=1;
54     for(i=last[rt];i;i=e[i].pre)if(!del[e[i].too])POI=sz[e[i].too],work(e[i].too);
55 }
56
57 inline void insert(int a,int b,int c){
58     e[++tot].too=b,e[tot].dis=c,e[tot].pre=last[a],last[a]=tot;
59     e[++tot].too=a,e[tot].dis=c,e[tot].pre=last[b],last[b]=tot;
60 }
61 bool cmp(zs a,zs b){return a.len>b.len;}
62
63 int main(){mx[0]=1e9;
64     n=read(),m=read();int m1=m;
65     for(i=1;i<n;i++)j=read(),k=read(),insert(j,k,read());
66     for(i=1;i<=m;i++)q[i].len=read(),q[i].id=i;
67     sort(q+1,q+1+m,cmp);
68     while(m&&q[m].len==0)q[m].done=1,m--;
69     POI=n,work(1);
70     for(i=1;i<=m;i++)gg[q[i].id]=1;
71     for(i=1;i<=m1;i++)puts(gg[i]?"No":"Yes");
72     return 0;
73 }

时间: 2024-11-05 05:53:43

[bzoj1316] 树上的询问的相关文章

[bzoj1316]树上的询问_点分治

树上的询问 bzoj-1316 题目大意:一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No. 注释:$1\le n\le 10^4$,$1\le p\le 100$,长度$\le 10^6$. 想法:有根树tm是啥意思?根在jb哪呢?老子我瞅tm这么半天也没看见根在哪呢??这题点分治即可.我们用点分治的第二种:分别计算子树,然后用之前的信息更新答案.对于此题,我们可以直接维护一个set就行. 最后,附上丑陋的代码... ... #inc

【点分治】bzoj1316 树上的询问

#include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define MAXN 10001 #define INF 2147483647 typedef pair<int,int> Point; int n,m,Ks[101]; bool vis[101]; int v[MAXN<<1],w[MAXN<<1],first[MAXN],ne

【BZOJ1316】树上的询问 点分治+set

[BZOJ1316]树上的询问 Description 一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No. Input 第一行两个整数n, p分别表示点的个数和询问的个数. 接下来n-1行每行三个数x, y, c,表示有一条树边x→y,长度为c. 接下来p行每行一个数Len,表示询问树中是否存在一条长度为Len的路径. Output 输出有p行,Yes或No. Sample Input 6 4 1 2 5 1 3 7 1 4 1 3 5

【bzoj1316】树上的询问 树的点分治+STL-set

题目描述 一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No. 输入 第一行两个整数n, p分别表示点的个数和询问的个数. 接下来n-1行每行三个数x, y, c,表示有一条树边x→y,长度为c. 接下来p行每行一个数Len,表示询问树中是否存在一条长度为Len的路径. 输出 输出有p行,Yes或No. 样例输入 6 4 1 2 5 1 3 7 1 4 1 3 5 2 3 6 3 1 8 13 14 样例输出 Yes Yes No Yes

NKOJ P3815 树上的询问 (LCA 倍增)(复习距离倍增)

评测说明 : 1000ms 问题描述 现有一棵 n 个节点的树,树上每条边的长度均为 1.给出 m 个询问,每次询问两个节 点 x,y,求树上到 x,y 两个点距离相同的节点数量. 输入格式 第一个整数 n,表示树有 n 个点. 接下来 n-1 行每行两整数 a,b,表示从 a 到 b 有一条边. 接下来一行一个整数 m,表示有 m 个询问. 接下来 m 行每行两整数 x,y,询问到 x 和 y 距离相同的点的数量. 输出格式 共 m 行,每行一个整数表示询问的答案. 样例输入 7 1 2 1 

cqyz oj | 树上的询问 | 最近公共祖先

Description 现有一棵 n 个节点的棵, 树上每条边的长度均为 1. 给出 m 个询问, 每次询问两个节点 x,y, 求树上到 x,y 两个点距离相同的节点数量. Input 第一个整数 n, 表示树有 n 个点. 接下来 n-1 行每行两整数 a, b, 表示从 a 到 b 有一条边. 接下来一行一个整数 m, 表示有 m 个询问. 接下来 m 行每行两整数 x, y, 询问到 x 和 y 距离相同的点的数量. Output 共 m 行, 每行一个整数表示询问的答案. Sample

ac自动机fail树上按询问建立上跳指针——cf963D

解法看着吓人,其实就是为了优化ac自动机上暴力跳fail指针.. 另外这题对于复杂度的分析很有学习价值 /* 给定一个母串s,再给定n个询问(k,m) 对于每个询问,求出长度最小的t,使t是s的子串,且m作为子串在t中出现了m次 对多串建立ac自动机,然后用s去匹配,把所有询问的出现位置都用vector保存下来 然后对应每个询问的k进行更新答案 为了保证复杂度:在跳fail不能暴力向上跳,应该直接用一个指针pre跳到上一个带有询问的点 这样每次向上跳都让某个询问的vector更新进一个新的值 由

[POJ 1316] 树上的询问

[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1316 [算法] 点分治 由于边权较大,笔者在计算时使用了STL-set 注意当询问为0时,要输出"Yes" [代码] #include<bits/stdc++.h> using namespace std; #define MAXN 10010 #define MAXQ 110 struct Edge { int to,w,nxt; } e[MAXN<&

BZOJ 1316: 树上的询问 (点分治+set)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1316 因为只要求存在某条路径长度为K,所以点分,然后用set判断差值是否在set中就可以了. #include<cstring>#include<algorithm>#include<iostream>#include<cstdio>#include<queue>#include<set>#include<cmath>