zoukankan      html  css  js  c++  java
  • [配套题解] 点分治配套题解

    这是 [点分治] 点分治入门 和 [模板] 点分治 的题解

    入口:

    [点分治] 点分治入门 : https://www.cnblogs.com/Railgun000/p/12597057.html

    [模板] 点分治 : https://www.cnblogs.com/Railgun000/p/12810246.html

    配套训练赛:https://vjudge.net/contest/362994#overview

    题单:

    POJ 1655

    POJ 2114

    POJ 1741

    HDU 4812

    HYSBZ 2152

    HDU 5977

    POJ 1987

    题解:

    A - Balancing Act

     POJ - 1655 

     

     1 #include<stdio.h>
     2 #include<iostream>
     3 #include<cstring>
     4 using namespace std;
     5 typedef long long ll;
     6 const int amn=1e5+5,inf=2e9;
     7 
     8 int n;
     9 
    10 int head[amn],etot;
    11 struct edge{
    12     int nxt,v;
    13     edge(){}
    14     edge(int nxt,int v):nxt(nxt),v(v){}
    15 }eg[amn];
    16 void init(){
    17     etot=0;
    18     memset(head,0,sizeof head);
    19 }
    20 void add(int u,int v){
    21     eg[++etot]=edge(head[u],v);
    22     head[u]=etot;
    23 }
    24 
    25 int siz[amn],maxt[amn];
    26 void calsiz(int u,int fa,int sum){
    27     siz[u]=1;
    28     maxt[u]=0;
    29     for(int i=head[u];i;i=eg[i].nxt){
    30         int v=eg[i].v;
    31         if(v==fa)continue;
    32         calsiz(v,u,sum);
    33         siz[u]+=siz[v];
    34         maxt[u]=max(maxt[u],siz[v]);
    35     }
    36     maxt[u]=max(maxt[u],sum-siz[u]);
    37 }
    38 
    39 int main(){
    40     int t;scanf("%d",&t);
    41     int u,v,ans1,ans2;
    42     while(t--){
    43         init();
    44         scanf("%d",&n);
    45         for(int i=1;i<n;i++){
    46             scanf("%d%d",&u,&v);
    47             add(u,v);
    48             add(v,u);
    49         }
    50         calsiz(1,-1,n);
    51         ans2=inf;
    52         for(int i=1;i<=n;i++){
    53             if(maxt[i]<ans2){
    54                 ans1=i;
    55                 ans2=maxt[i];
    56             }
    57         }
    58         printf("%d %d
    ",ans1,ans2);
    59     }
    60 }
    61 
    62 /**
    63 题意:
    64 给一个树,
    65 去掉树上的一个节点,
    66 求最大子树结点数的最小值,
    67 如果有多个点都是最小值,
    68 那么找一个序号最小的节点。
    69 输出节点号,和最小值。
    70 
    71 分析:
    72 求树的重心模板题,
    73 1遍dfs求处每个结点的最大子树结点数,
    74 为了使序号最小,则从结点1开始maxt数组找一个最小值.
    75 注意这里有多组输入,则每次要初始化链式前向星的etot和head数组.
    76 */

    B - Boatherds

     POJ - 2114

     

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 #include<queue>
      5 using namespace std;
      6 const int amn=1e5+5,inf=1e9;
      7 int n,m,K[amn];
      8 
      9 int head[amn],etot;
     10 struct edge{
     11     int nxt,v,w;
     12     edge(){}
     13     edge(int nxt,int v,int w):nxt(nxt),v(v),w(w){}
     14 }eg[amn];
     15 void init(){
     16     etot=0;
     17     memset(head,0,sizeof head);
     18 }
     19 void add(int u,int v,int w){
     20     eg[++etot]=edge(head[u],v,w);
     21     head[u]=etot;
     22 }
     23 
     24 int siz[amn],maxt[amn],vis[amn],rt;
     25 void calsiz(int u,int fa,int sum){
     26     siz[u]=1;
     27     maxt[u]=0;
     28     for(int i=head[u];i;i=eg[i].nxt){
     29         int v=eg[i].v;
     30         if(vis[v]||v==fa)continue;
     31         calsiz(v,u,sum);
     32         siz[u]+=siz[v];
     33         maxt[u]=max(maxt[u],siz[v]);
     34     }
     35     maxt[u]=max(maxt[u],sum-siz[u]);
     36     if(maxt[u]<maxt[rt])rt=u;
     37 }
     38 void getroot(int u,int fa,int sum){
     39     rt=0;
     40     maxt[rt]=inf;
     41     calsiz(u,fa,sum);
     42     calsiz(rt,-1,sum);
     43 }
     44 
     45 int dis[amn],di[amn],tp;
     46 void caldis(int u,int fa){
     47     if(dis[u]>(int)1e7)return;
     48     di[++tp]=dis[u];
     49     for(int i=head[u];i;i=eg[i].nxt){
     50         int v=eg[i].v,w=eg[i].w;
     51         if(vis[v]||v==fa)continue;
     52         dis[v]=dis[u]+w;
     53         caldis(v,u);
     54     }
     55 }
     56 
     57 bool jg[(int)1e7+5];
     58 int ans[amn];
     59 queue<int> bk;
     60 void sovle(int u){
     61     jg[0]=1;
     62     bk.push(0);
     63     for(int i=head[u];i;i=eg[i].nxt){
     64         int v=eg[i].v,w=eg[i].w;
     65         if(vis[v])continue;
     66         tp=0;
     67         dis[v]=w;
     68         caldis(v,u);
     69         for(int j=1;j<=tp;j++){
     70             for(int k=1;k<=m;k++){
     71                 if(K[k]>=di[j])ans[k]+=jg[K[k]-di[j]];
     72             }
     73         }
     74         for(int j=1;j<=tp;j++){
     75             jg[di[j]]=1;
     76             bk.push(di[j]);
     77         }
     78     }
     79     while(bk.size()){
     80         jg[bk.front()]=0;
     81         bk.pop();
     82     }
     83 }
     84 void dfz(int u){
     85     vis[u]=1;
     86     sovle(u);
     87     for(int i=head[u];i;i=eg[i].nxt){
     88         int v=eg[i].v;
     89         if(vis[v])continue;
     90         getroot(v,u,siz[v]);
     91         dfz(rt);
     92     }
     93 }
     94 int main(){
     95     int a,b;
     96     while(~scanf("%d",&n)&&n){
     97         init();
     98         for(int i=1;i<=n;i++){
     99             while(scanf("%d",&a)&&a){
    100                 scanf("%d",&b);
    101                 add(i,a,b);
    102                 add(a,i,b);
    103             }
    104         }
    105         m=0;
    106         while(scanf("%d",&K[++m])&&K[m]);
    107         m--;
    108         memset(vis,0,sizeof vis);
    109         memset(ans,0,sizeof ans);
    110         getroot(1,-1,n);
    111         dfz(rt);
    112         for(int i=1;i<=m;i++){
    113             if(ans[i])printf("AYE
    ");
    114             else printf("NAY
    ");
    115         }
    116         puts(".");
    117     }
    118 }
    119 /**
    120 题意:
    121 求一棵树上是否存在路径长度为K的点对。
    122 
    123 分析:
    124 和ppt里的做法一样,只是输入和输出有区别
    125 多组输入,注意初始化
    126 每个case最后单独一行输出一个'.'
    127 */

     

    C - Tree

     POJ - 1741

     

      1 #include<stdio.h>
      2 #include<iostream>
      3 #include<queue>
      4 #include<string.h>
      5 #include<algorithm>
      6 using namespace std;
      7 typedef long long ll;
      8 const int amn=2e5+5,inf=2e9,top=2e4+5;
      9 
     10 int n,a,b,c,k;
     11 
     12 int head[amn],etot;
     13 struct edge{
     14     int nxt,v,w;
     15     edge(){}
     16     edge(int nxt,int v,int w):nxt(nxt),v(v),w(w){}
     17 }eg[amn];
     18 void add(int u,int v,int w){
     19     eg[++etot]=edge(head[u],v,w);
     20     head[u]=etot;
     21 }
     22 
     23 int siz[amn],maxt[amn],rt,vis[amn];
     24 void calsiz(int u,int fa,int sum){
     25     siz[u]=1;
     26     maxt[u]=0;
     27     for(int i=head[u];i;i=eg[i].nxt){
     28         int v=eg[i].v;
     29         if(vis[v]||v==fa)continue;
     30         calsiz(v,u,sum);
     31         siz[u]+=siz[v];
     32         maxt[u]=max(maxt[u],siz[v]);
     33     }
     34     maxt[u]=max(maxt[u],sum-siz[u]);
     35     if(maxt[u]<maxt[rt])rt=u;
     36 }
     37 void getroot(int u,int fa,int sum){
     38     rt=0;
     39     maxt[rt]=inf;
     40     calsiz(u,fa,sum);
     41     calsiz(rt,-1,sum);
     42 }
     43 
     44 int dis[amn],di[amn],tp;
     45 void caldis(int u,int fa){
     46     if(dis[u]>k)return ;    ///防溢出
     47     di[++tp]=dis[u];
     48     for(int i=head[u];i;i=eg[i].nxt){
     49         int v=eg[i].v,w=eg[i].w;
     50         if(vis[v]||v==fa)continue;
     51         dis[v]=dis[u]+w;
     52         caldis(v,u);
     53     }
     54 }
     55 
     56 int sovle(int u,int fa,int w){
     57     dis[u]=w;
     58     tp=0;///记得要初始化栈!!!
     59     caldis(u,fa);
     60     sort(di+1,di+1+tp);
     61     int l=1,r=tp,ans=0;
     62     while(l<r){
     63         if(di[l]+di[r]<=k){
     64             ans+=r-l;
     65             l++;
     66         }
     67         else r--;
     68     }
     69     return ans;
     70 }
     71 
     72 int ans;
     73 void dfz(int u){
     74     vis[u]=1;
     75     ans+=sovle(u,-1,0);
     76     for(int i=head[u];i;i=eg[i].nxt){
     77         int v=eg[i].v,w=eg[i].w;
     78         if(vis[v])continue;
     79         ans-=sovle(v,u,w);
     80         getroot(v,u,siz[v]);
     81         dfz(rt);
     82     }
     83 }
     84 
     85 void init(){
     86     etot=0;
     87     memset(head,0,sizeof head);
     88     ans=0;
     89     memset(vis,0,sizeof vis);///每次要初始化标记数组,这个要注意,多组输入的题要拿相同数据多试几遍看输出是否正常
     90 }
     91 
     92 int main(){
     93     while(~scanf("%d%d",&n,&k)&&n&&k){
     94         init();
     95         for(int i=1;i<n;i++){
     96             scanf("%d%d%d",&a,&b,&c);
     97             add(a,b,c);
     98             add(b,a,c);
     99         }
    100         getroot(1,-1,n);
    101         dfz(rt);
    102         printf("%d
    ",ans);
    103     }
    104 }
    105 /**
    106 题意:
    107 求一棵树上路径长度大于等于1且小于等于K的点对个数。
    108 
    109 分析:
    110 和ppt里的做法一样,这里选择双指针法
    111 多组输入,注意初始化
    112 */

     

    D - D Tree

     HDU - 4812

     

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 #include<queue>
      5 using namespace std;
      6 const int amn=5e5+5,inf=2e9,mod=1e6+3;
      7 typedef long long ll;
      8 
      9 int n,ansx,ansy;
     10 ll V[amn],inv[(int)(mod+5)],K;
     11 
     12 int head[amn],etot;
     13 struct edge{
     14     int to,v;
     15     edge(){}
     16     edge(int to,int v):to(to),v(v){}
     17 }eg[amn];
     18 void add(int u,int v){
     19     eg[++etot]=edge(head[u],v);
     20     head[u]=etot;
     21 }
     22 
     23 int siz[amn],maxt[amn],rt,vis[amn];
     24 void calsiz(int u,int fa,int sum){
     25     siz[u]=1;
     26     maxt[u]=0;
     27     for(int i=head[u];i;i=eg[i].to){
     28         int v=eg[i].v;
     29         if(vis[v]||v==fa)continue;
     30         calsiz(v,u,sum);
     31         siz[u]+=siz[v];
     32         maxt[u]=max(maxt[u],siz[v]);
     33     }
     34     maxt[u]=max(maxt[u],sum-siz[u]);
     35     if(maxt[u]<maxt[rt])rt=u;
     36 }
     37 void getroot(int u,int fa,int sum){
     38     rt=0;
     39     maxt[rt]=inf;
     40     calsiz(u,fa,sum);
     41 }
     42 
     43 ll dis[amn],di[amn],tp;
     44 void caldis(int u,int fa){
     45     di[++tp]=u;
     46     for(int i=head[u];i;i=eg[i].to){
     47         int v=eg[i].v;
     48         if(vis[v]||v==fa)continue;
     49         dis[v]=V[v]*dis[u]%mod;
     50         caldis(v,u);
     51     }
     52 }
     53 
     54 int tf[(int)(mod+5)];
     55 queue<int> bk;
     56 void sovle(int u){
     57     tf[1]=u;
     58     bk.push(1);
     59     for(int i=head[u];i;i=eg[i].to){
     60         int v=eg[i].v;
     61         if(vis[v])continue;
     62         tp=0;
     63         dis[v]=V[v];
     64         caldis(v,u);
     65         for(int j=1;j<=tp;j++){
     66             ll x=di[j],y=tf[K*inv[dis[x]*V[u]%mod]%mod];
     67             if(!y)continue;
     68             if(x>y)swap(x,y);
     69             if(x<ansx||(x==ansx&&y<ansy))
     70                 ansx=x,ansy=y;
     71         }
     72         for(int j=1;j<=tp;j++){
     73             if(!tf[dis[di[j]]]||di[j]<tf[dis[di[j]]]){
     74                 tf[dis[di[j]]]=di[j];
     75                 bk.push(dis[di[j]]);
     76             }
     77         }
     78     }
     79     while(bk.size()){
     80         tf[bk.front()]=0;
     81         bk.pop();
     82     }
     83 }
     84 
     85 void dfz(int u){
     86     vis[u]=1;
     87     sovle(u);
     88     for(int i=head[u];i;i=eg[i].to){
     89         int v=eg[i].v;
     90         if(vis[v])continue;
     91         getroot(v,u,siz[v]);
     92         dfz(rt);
     93     }
     94 }
     95 
     96 void init(int n){
     97     ansx=ansy=inf;
     98     etot=0;
     99     memset(head,0,sizeof head);
    100     memset(vis,0,sizeof vis);
    101 }
    102 
    103 int main(){
    104     inv[1]=1;
    105     for(int i=2;i<=mod;i++)
    106         inv[i]=(1LL*(-(mod/i)*inv[mod%i]%mod+mod)%mod);
    107     while(~scanf("%d%d",&n,&K)){
    108         init(n);
    109         for(int i=1;i<=n;i++){
    110             scanf("%lld",&V[i]);
    111         }
    112         for(int i=1;i<n;i++){
    113             int x,y;
    114             scanf("%d%d",&x,&y);
    115             add(x,y);
    116             add(y,x);
    117         }
    118         getroot(1,-1,n);
    119         dfz(rt);
    120         if(ansx==inf)printf("No solution
    ");
    121         else printf("%d %d
    ",ansx,ansy);
    122     }
    123 }
    124 /**
    125 题意:
    126 在树上找一条链,使得链上点权值的乘积对1e6+3取模为k,输出两个端点,若有相同情况输出字典序最小的编号.
    127 
    128 分析:
    129 
    130 dis[x]*dis[y]%mod==K
    131         |
    132         v
    133 dis[y]==K*inv[dis[x]]%mod
    134 
    135 用类似判断是否有路径和等于k的方法
    136 caldis函数的di数组改为统计端点的编号,
    137 solve函数的tf数组改为存端点的编号
    138 */

     

    E - 聪聪可可

     HYSBZ - 2152

     

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 const int amn=1e5+5,inf=1e9;
      5 
      6 int n,a,b,c;
      7 
      8 int head[amn],egnum;
      9 struct edge{
     10     int nxt,v,w;
     11     edge(){}
     12     edge(int nxt,int v,int w):nxt(nxt),v(v),w(w){}
     13 }eg[amn];
     14 void add(int u,int v,int w){
     15     eg[++egnum]=edge(head[u],v,w);
     16     head[u]=egnum;
     17 }
     18 
     19 int siz[amn],maxt[amn],rt,vis[amn];
     20 void calsiz(int u,int fa,int sum){
     21     siz[u]=1;
     22     maxt[u]=0;
     23     for(int i=head[u];i;i=eg[i].nxt){
     24         int v=eg[i].v;
     25         if(vis[v]||v==fa)continue;
     26         calsiz(v,u,sum);
     27         siz[u]+=siz[v];
     28         maxt[u]=max(maxt[u],siz[v]);
     29     }
     30     maxt[u]=max(maxt[u],sum-siz[u]);
     31     if(maxt[u]<maxt[rt])rt=u;
     32 }
     33 void getroot(int u,int fa,int sum){
     34     rt=0;
     35     maxt[rt]=inf;
     36     calsiz(u,fa,sum);
     37     calsiz(rt,-1,sum);
     38 }
     39 
     40 int dis[amn],di[amn],tp;
     41 void caldis(int u,int fa){
     42     di[++tp]=dis[u];
     43     for(int i=head[u];i;i=eg[i].nxt){
     44         int v=eg[i].v,w=eg[i].w;
     45         if(vis[v]||v==fa)continue;
     46         dis[v]=dis[u]+w;
     47         caldis(v,u);
     48     }
     49 }
     50 
     51 int jg[5],ans;
     52 void solve(int u){
     53     for(int i=head[u];i;i=eg[i].nxt){
     54         int v=eg[i].v,w=eg[i].w;
     55         if(vis[v])continue;
     56         tp=0;
     57         dis[v]=w;
     58         caldis(v,u);
     59         for(int j=1;j<=tp;j++){
     60             ans+=2*((di[j]%3==0?1:0)+jg[(3-di[j]%3+3)%3]);
     61         }
     62         for(int j=1;j<=tp;j++){
     63             jg[di[j]%3]++;
     64         }
     65     }
     66     jg[0]=jg[1]=jg[2]=0;
     67 }
     68 void dfz(int u){
     69     vis[u]=1;
     70     solve(u);
     71     for(int i=head[u];i;i=eg[i].nxt){
     72         int v=eg[i].v,w=eg[i].w;
     73         if(vis[v])continue;
     74         getroot(v,u,siz[v]);
     75         dfz(rt);
     76     }
     77 }
     78 
     79 int gcd(int a,int b){
     80     return b?gcd(b,a%b):a;
     81 }
     82 
     83 int main(){
     84     scanf("%d",&n);
     85     for(int i=1;i<n;i++){
     86         scanf("%d%d%d",&a,&b,&c);
     87         add(a,b,c);
     88         add(b,a,c);
     89     }
     90     ans=n;
     91     getroot(1,-1,n);
     92     dfz(rt);
     93     int fm=n*n;
     94     int g=gcd(ans,fm);
     95     printf("%d/%d
    ",ans/g,fm/g);
     96 }
     97 /**
     98 题意:
     99 给一颗树,有n给点,两个点之间所有边上数的和加起来恰好是3的倍数的概率,用最简分数形式输出
    100 
    101 分析:
    102 求出两个点之间所有边上数的和加起来恰好是3的倍数的数量,和所有路径数n*n求gcd即可
    103 所以问题是如何求路径距离为3的倍数的数量
    104 如果一个数a是3的倍数,则a%3==0
    105 如果数b和c不是3的倍数,则b%3==1,c%3==2
    106 那么3的倍数有下列情况:a%3==0,(a+a)%3==0,(b+c)%3==0
    107 按照求路径距离为k的个数的方法改下sovle函数就行了
    108 注意这里是有向路径,而我们只算了一个方向,所以中累加答案时要乘2
    109 */

     

    F - Garden of Eden

     HDU - 5977

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 using namespace std;
      5 typedef long long ll;
      6 const int amn=1e5+5,inf=2e9;
      7 
      8 int n,k;
      9 ll ans;
     10 
     11 int head[amn],egnum,type[amn];
     12 struct edge{
     13     int to,v;
     14     edge(){}
     15     edge(int to,int v):to(to),v(v){}
     16 }eg[amn];
     17 void add(int u,int v){
     18     eg[++egnum]=edge(head[u],v);
     19     head[u]=egnum;
     20 }
     21 void add_eg(int u,int v){
     22     add(u,v);
     23     add(v,u);
     24 }
     25 
     26 int siz[amn],maxt[amn],rt;bool vis[amn];
     27 void calsiz(int u,int fa,int sum){
     28     siz[u]=1;
     29     maxt[u]=0;
     30     for(int i=head[u];i;i=eg[i].to){
     31         int v=eg[i].v;
     32         if(v==fa||vis[v])continue;
     33         calsiz(v,u,sum);
     34         siz[u]+=siz[v];
     35         maxt[u]=max(maxt[u],siz[v]);
     36     }
     37     maxt[u]=max(maxt[u],sum-siz[u]);
     38     if(maxt[u]<maxt[rt])rt=u;
     39 }
     40 void getroot(int u,int fa,int sum){
     41     rt=0;
     42     maxt[rt]=inf;
     43     calsiz(u,fa,sum);
     44 }
     45 
     46 ll di[amn],tp,cnt;
     47 void caldis(int u,int fa,ll cnt){
     48     di[++tp]=cnt;
     49     for(int i=head[u];i;i=eg[i].to){
     50         int v=eg[i].v;
     51         if(v==fa||vis[v])continue;
     52         caldis(v,u,cnt|(1<<(type[v]-1)));
     53     }
     54 }
     55 ll tf[3000];
     56 ll tot;
     57 ll sovle(int u,int fa){
     58     ll an=0;
     59     tp=0;
     60     caldis(u,fa,(1<<(type[u]-1))|(1<<(type[fa]-1)));
     61     for(int i=1;i<=tp;i++)tf[di[i]]++;  ///处理了所有路径情况
     62     for(int i=1;i<=tp;i++){
     63         tf[di[i]]--;    ///这里是当前路径与其他路径组合,所以要减掉自身
     64         an+=tf[tot];
     65         for(int j=di[i];j;j=((j-1)&di[i]))an+=tf[tot^j];    ///枚举di[i]状态的子集
     66         tf[di[i]]++;    ///还原自身
     67     }
     68     for(int i=1;i<=tp;i++){
     69         tf[di[i]]=0;
     70     }
     71     return an;
     72 }
     73 void dfz(int u){
     74     vis[u]=1;
     75     ans+=sovle(u,u);
     76     for(int i=head[u];i;i=eg[i].to){
     77         int v=eg[i].v;
     78         if(vis[v])continue;
     79         ans-=sovle(v,u);        ///sovle函数算了rt结点,所以要减掉不合法的情况,详情见ppt双指针的内容
     80         getroot(v,u,siz[v]);
     81         dfz(rt);
     82     }
     83 }
     84 void init(int n){
     85     ans=egnum=0;
     86     for(int i=1;i<=n;i++)head[i]=vis[i]=0;
     87     tot=(1<<k)-1;
     88 }
     89 
     90 int main(){
     91     while(~scanf("%d%d",&n,&k)){
     92         init(n);
     93         for(int i=1;i<=n;i++){
     94             scanf("%d",&type[i]);
     95         }
     96         int u,v;
     97         for(int i=1;i<n;i++){
     98 
     99             scanf("%d%d",&u,&v);
    100             add_eg(u,v);
    101         }
    102         if(k==1){printf("%d
    ",n*n);continue;}
    103         getroot(1,-1,n);
    104         dfz(rt);
    105         printf("%lld
    ",ans);
    106     }
    107 }
    108 /**
    109 题意:
    110 给一棵树,树上有K种苹果,
    111 问从任意点出发,到任意点结束,
    112 把路径上的所有苹果种类取全,
    113 能够取全K种苹果的有向点对数(1->2和2->1是不同的)
    114 
    115 分析:
    116 我们需要记录每个点到根节点的路径上取到的苹果的种类
    117 再看这条路径是否把苹果种类取全,
    118 或它能与其他子树的哪些路径互补使得这条组合路径把苹果种类取全
    119 注意,如果一条路径把苹果取全后,那么它能与任意其他子树的哪些路径互补使得这条组合路径把苹果种类取全
    120 因为它本来就是种类齐全的
    121 如果用二进制表示,就像这样( | 是或运算):1111 | 0001 = 1111, 1111 | 0011 = 1111,
    122 这就启发了我们使用二进制来表示路径取苹果种类的状态,
    123 每条路径状态都可以与全1状态互补为全1状态,每条路径算答案时都要加上当前全1状态路径数
    124 
    125 我们知道,^是异或运算,a^b==c , b==c^a ,也就是说,已知c和a就可以通过异或求出b,
    126 这就启发了我们用异或来查询其他子树的路径状态数
    127 
    128 由前面分析的种类齐全的情况,
    129 启发了我们如果得到一个路径状态a,
    130 那么a的子集也由可能与其他子树的路径互补为全1状态
    131 */

    G - Distance Statistics

     POJ - 1987

      1 #include<stdio.h>
      2 #include<iostream>
      3 #include<queue>
      4 #include<string.h>
      5 #include<algorithm>
      6 using namespace std;
      7 typedef long long ll;
      8 const int amn=2e5+5,inf=2e9,top=2e4+5;
      9 
     10 int n,m,a,b,c,k;
     11 
     12 int head[amn],etot;
     13 struct edge{
     14     int nxt,v,w;
     15     edge(){}
     16     edge(int nxt,int v,int w):nxt(nxt),v(v),w(w){}
     17 }eg[amn];
     18 void add(int u,int v,int w){
     19     eg[++etot]=edge(head[u],v,w);
     20     head[u]=etot;
     21 }
     22 
     23 int siz[amn],maxt[amn],rt,vis[amn];
     24 void calsiz(int u,int fa,int sum){
     25     siz[u]=1;
     26     maxt[u]=0;
     27     for(int i=head[u];i;i=eg[i].nxt){
     28         int v=eg[i].v;
     29         if(vis[v]||v==fa)continue;
     30         calsiz(v,u,sum);
     31         siz[u]+=siz[v];
     32         maxt[u]=max(maxt[u],siz[v]);
     33     }
     34     maxt[u]=max(maxt[u],sum-siz[u]);
     35     if(maxt[u]<maxt[rt])rt=u;
     36 }
     37 void getroot(int u,int fa,int sum){
     38     rt=0;
     39     maxt[rt]=inf;
     40     calsiz(u,fa,sum);
     41     calsiz(rt,-1,sum);
     42 }
     43 
     44 int dis[amn],di[amn],tp;
     45 void caldis(int u,int fa){
     46     if(dis[u]>k)return ;    ///防溢出
     47     di[++tp]=dis[u];
     48     for(int i=head[u];i;i=eg[i].nxt){
     49         int v=eg[i].v,w=eg[i].w;
     50         if(vis[v]||v==fa)continue;
     51         dis[v]=dis[u]+w;
     52         caldis(v,u);
     53     }
     54 }
     55 
     56 int sovle(int u,int fa,int w){
     57     dis[u]=w;
     58     tp=0;///记得要初始化栈!!!
     59     caldis(u,fa);
     60     sort(di+1,di+1+tp);
     61     int l=1,r=tp,ans=0;
     62     while(l<r){
     63         if(di[l]+di[r]<=k){
     64             ans+=r-l;
     65             l++;
     66         }
     67         else r--;
     68     }
     69     return ans;
     70 }
     71 
     72 int ans;
     73 void dfz(int u){
     74     vis[u]=1;
     75     ans+=sovle(u,-1,0);
     76     for(int i=head[u];i;i=eg[i].nxt){
     77         int v=eg[i].v,w=eg[i].w;
     78         if(vis[v])continue;
     79         ans-=sovle(v,u,w);
     80         getroot(v,u,siz[v]);
     81         dfz(rt);
     82     }
     83 }
     84 
     85 void init(){
     86     etot=0;
     87     memset(head,0,sizeof head);
     88     ans=0;
     89     memset(vis,0,sizeof vis);///每次要初始化标记数组,这个要注意,多组输入的题要拿相同数据多试几遍看输出是否正常
     90 }
     91 
     92 int main(){
     93     char in;
     94     while(~scanf("%d%d",&n,&m)){
     95         init();
     96         for(int i=1;i<=m;i++){
     97             scanf("%d%d%d %c",&a,&b,&c,&in);
     98             add(a,b,c);
     99             add(b,a,c);
    100         }
    101         scanf("%d",&k);
    102         getroot(1,-1,n);
    103         dfz(rt);
    104         printf("%d
    ",ans);
    105     }
    106 }
    107 /**
    108 题意:
    109 求一棵树上路径长度大于等于1且小于等于K的点对个数。
    110 
    111 分析:
    112 和ppt里的做法一样,这里选择双指针法
    113 多组输入,注意初始化
    114 和poj1741不同的是K (1 <= K <= 1,000,000,000)变为最大到1e9了,输入也有不同
    115 */
  • 相关阅读:
    机器学习-数据归一化及哪些算法需要归一化
    目标检测中的mAP
    在Ubuntu内制作自己的VOC数据集
    目标检测算法之YOLOv3
    目标检测算法之YOLOv1与v2
    详谈Windows消息循环机制
    位和字节以及各类编码简述
    C++ 基础知识(一)
    Python 爬取高清桌面壁纸
    WPF 动画执行后属性无法修改
  • 原文地址:https://www.cnblogs.com/Railgun000/p/12810520.html
Copyright © 2011-2022 走看看