zoukankan      html  css  js  c++  java
  • 1316: 树上的询问(点分治)

    1316: 树上的询问

    链接

    分析

      每次查找出重心(去掉重心后的最大的联通块最小,保证复杂度),然后统计过重心的路径中有没有长度等于len的。

      统计时,由于必须要过重心,不能是同一棵子树中的。可以挨个遍历每棵子树,然后统计即可。

      判断时,用set查找一下即可。

    代码

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cctype>
      4 #include<set>
      5  
      6 using namespace std;
      7  
      8 const int N = 10010;
      9  
     10 struct Edge{
     11     int to,nxt,w;
     12     Edge() {}
     13     Edge(int a,int b,int c) {to = a,w = b,nxt = c;}
     14 }e[N<<1];
     15 int A[N],q[N],ans[N],dis[N],deth[N],head[N],siz[N];
     16 int tot,Root,Size,Cnt,Num = 1e9,n,m;
     17 bool vis[N];
     18 set<int>s;
     19  
     20 inline int read() {
     21     int x = 0,f = 1;char ch=getchar();
     22     for (; !isdigit(ch); ch=getchar()) if(ch=='-')f=-1;
     23     for (; isdigit(ch); ch=getchar()) x=x*10+ch-'0';
     24     return x*f;
     25 }
     26 void add_edge(int u,int v,int w) {
     27     e[++tot] = Edge(v,w,head[u]);head[u] = tot;
     28     e[++tot] = Edge(u,w,head[v]);head[v] = tot;
     29 }
     30 void getRoot(int u,int fa) {
     31     siz[u] = 1;
     32     int mx = 0;
     33     for (int i=head[u]; i; i=e[i].nxt) {
     34         int v = e[i].to;
     35         if (v == fa || vis[v]) continue;
     36         getRoot(v,u);
     37         siz[u] += siz[v];
     38         mx = max(siz[v],mx);
     39     }
     40     mx = max(mx,Size-siz[u]);
     41     if (mx < Num) Root = u,Num = mx;
     42 }   
     43 void dfs(int u,int fa) {
     44     A[++Cnt] = dis[u];
     45     for (int i=head[u]; i; i=e[i].nxt) {
     46         int v = e[i].to;
     47         if (v == fa || vis[v]) continue;
     48         dis[v] = dis[u] + e[i].w;
     49         dfs(v,u);
     50     }
     51 }
     52 void calcc(int u) {
     53     s.clear();
     54     s.insert(0);
     55     dis[u] = 0;
     56     for (int i=head[u]; i; i=e[i].nxt) {
     57         int v = e[i].to;
     58         if (vis[v]) continue;
     59         Cnt = 0;
     60         dis[v] = e[i].w;
     61         dfs(v,u);
     62         for (int j=1; j<=Cnt; ++j) {
     63             for (int k=1; k<=m; ++k) {
     64                 if (ans[k]) continue;
     65                 if (s.find(q[k]-A[j])!=s.end()) ans[k] = 1;
     66             }
     67         }
     68         for (int j=1; j<=Cnt; ++j) s.insert(A[j]);
     69     }
     70 }
     71 void solve(int u) {
     72     vis[u] =  true;
     73     calcc(u);
     74     for (int i=head[u]; i; i=e[i].nxt) {
     75         int v = e[i].to;
     76         if (vis[v]) continue;
     77         Size = siz[v];Num = 1e9;Root = 0;
     78         getRoot(v,0);
     79         solve(Root);
     80     }
     81 }
     82 int main() {
     83     n = read(),m = read();
     84     for (int u,v,w,i=1; i<n; ++i) {
     85         u = read(),v = read(),w = read();
     86         add_edge(u,v,w);
     87     }
     88     for (int i=1; i<=m; ++i) {
     89         q[i] = read();
     90         if (!q[i]) ans[i] = 1;
     91     }
     92     Size = n;
     93     Num = 1e9;
     94     getRoot(1,0);
     95     solve(Root);
     96     for (int i=1; i<=m; ++i) 
     97         if (ans[i]) puts("Yes");
     98         else puts("No");
     99     return 0;
    100 }
  • 相关阅读:
    AutoCAD利用VBA设置线型和添加用户自定义线性
    AutoVBA利用for循环创建同心圆弧
    AutoVBA利用Hacth对象填充图元对象
    AutoVBA利用AddArc方法创建Arc对象
    2011年6月5日星期天
    AutoVBA控件的tabindex和tabstop属性及with语句
    AutoVBA在绘图空间创建直线对象
    AutoVBA利用toolbar创建自己的工具栏
    AutoVBA调用AddCricle方法绘制圆
    AutoCAD利用VBA宏绘制多重平行线
  • 原文地址:https://www.cnblogs.com/mjtcn/p/9124347.html
Copyright © 2011-2022 走看看