【算法总结】树相关

【点分治】

〖模板代码〗

 1 void getroot(int x,int fa)
 2 {
 3     sz[x]=1;mx[x]=0;
 4     for(int i=first[x];i;i=e[i].next)
 5     {
 6         int to=e[i].to;
 7         if(to==fa||vis[to])continue;
 8         getroot(to,x);
 9         sz[x]+=sz[to];
10         mx[x]=max(mx[x],sz[to]);
11     }
12     mx[x]=max(mx[x],sum-sz[x]);
13     if(mx[root]>mx[x])root=x;
14 }
15 void getdeep(int x,int fa)
16 {
17     d[++tot]=deep[x];
18     for(int i=first[x];i;i=e[i].next)
19     {
20         int to=e[i].to;
21         if(to==fa||vis[to])continue;
22         deep[to]=deep[x]+e[i].w;
23         getdeep(to,x);
24     }
25 }
26 int calc(int x)
27 {
28     tot=0;getdeep(x,-1);
29     sort(d+1,d+tot+1);
30     int ans=0,i=1,j=tot;
31     while(i<j)
32     {
33         if(d[i]+d[j]<=K)ans+=j-i,i++;
34         else j--;
35     }
36     return ans;
37 }
38 void dfs(int x)
39 {
40     deep[x]=0;vis[x]=true;ans+=calc(x);
41     for(int i=first[x];i;i=e[i].next)
42     {
43         int to=e[i].to;
44         if(vis[to])continue;
45         deep[to]=e[i].w;
46         ans-=calc(to);
47         sum=sz[to];root=0;
48         getroot(to,-1);dfs(root);
49     }
50 }
51 int main()
52 {
53     root=0;sum=n;mx[0]=inf;
54     getroot(1,-1);dfs(root);
55     printf("%d\n",ans);
56 }

〖相关题目〗

1.【poj1741】Tree

题意:给定一棵n个点的有边权的树,给定数字k,求满足x到y距离≤k的无序点对(x,y)的个数。

分析:GXZlegendの博客

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=1e4+5;
 6 const int inf=0x3f3f3f3f;
 7 int n,K,cnt,x,y,w,root,sum,ans,tot;
 8 int sz[N],mx[N],first[N],deep[N],d[N];
 9 bool vis[N];
10 struct edge{int to,next,w;}e[N<<1];
11 int read()
12 {
13     int x=0,f=1;char c=getchar();
14     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
15     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
16     return x*f;
17 }
18 void ins(int u,int v,int w){e[++cnt]=(edge){v,first[u],w};first[u]=cnt;}
19 void getroot(int x,int fa)
20 {
21     sz[x]=1;mx[x]=0;
22     for(int i=first[x];i;i=e[i].next)
23     {
24         int to=e[i].to;
25         if(to==fa||vis[to])continue;
26         getroot(to,x);
27         sz[x]+=sz[to];
28         mx[x]=max(mx[x],sz[to]);
29     }
30     mx[x]=max(mx[x],sum-sz[x]);
31     if(mx[root]>mx[x])root=x;
32 }
33 void getdeep(int x,int fa)
34 {
35     d[++tot]=deep[x];
36     for(int i=first[x];i;i=e[i].next)
37     {
38         int to=e[i].to;
39         if(to==fa||vis[to])continue;
40         deep[to]=deep[x]+e[i].w;
41         getdeep(to,x);
42     }
43 }
44 int calc(int x)
45 {
46     tot=0;getdeep(x,-1);
47     sort(d+1,d+tot+1);
48     int ans=0,i=1,j=tot;
49     while(i<j)
50     {
51         if(d[i]+d[j]<=K)ans+=j-i,i++;
52         else j--;
53     }
54     return ans;
55 }
56 void dfs(int x)
57 {
58     deep[x]=0;vis[x]=true;ans+=calc(x);
59     for(int i=first[x];i;i=e[i].next)
60     {
61         int to=e[i].to;
62         if(vis[to])continue;
63         deep[to]=e[i].w;
64         ans-=calc(to);
65         sum=sz[to];root=0;
66         getroot(to,-1);dfs(root);
67     }
68 }
69 int main()
70 {
71     n=read();K=read();
72     while(n||K)
73     {
74         cnt=0;ans=0;
75         memset(first,0,sizeof(first));
76         memset(vis,0,sizeof(vis));
77         for(int i=1;i<n;i++)
78         {
79             x=read();y=read();w=read();
80             ins(x,y,w);ins(y,x,w);
81         }
82         root=0;sum=n;mx[0]=inf;
83         getroot(1,-1);dfs(root);
84         printf("%d\n",ans);
85         n=read();K=read();
86     }
87     return 0;
88 }

2.【bzoj2152】聪聪可可

题意:给定一棵n个点的有边权的树,求满足x到y距离恰好是3的倍数的有序点对(x,y)的个数/有序点对总个数。

分析:点分治裸题

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=2e4+5;
 6 const int inf=0x3f3f3f3f;
 7 int n,cnt,x,y,w,root,sum,ans;
 8 int t[3],first[N],mx[N],sz[N],deep[N];
 9 bool vis[N];
10 struct edge{int to,next,w;}e[N<<1];
11 int read()
12 {
13     int x=0,f=1;char c=getchar();
14     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
15     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
16     return x*f;
17 }
18 void ins(int u,int v,int w){e[++cnt]=(edge){v,first[u],w};first[u]=cnt;}
19 void getroot(int x,int fa)
20 {
21     sz[x]=1;mx[x]=0;
22     for(int i=first[x];i;i=e[i].next)
23     {
24         int to=e[i].to;
25         if(to==fa||vis[to])continue;
26         getroot(to,x);
27         sz[x]+=sz[to];
28         mx[x]=max(mx[x],sz[to]);
29     }
30     mx[x]=max(mx[x],sum-sz[x]);
31     if(mx[root]>mx[x])root=x;
32 }
33 void getdeep(int x,int fa)
34 {
35     t[deep[x]]++;
36     for(int i=first[x];i;i=e[i].next)
37     {
38         int to=e[i].to;
39         if(to==fa||vis[to])continue;
40         deep[to]=(deep[x]+e[i].w)%3;
41         getdeep(to,x);
42     }
43 }
44 int calc(int x)
45 {
46     t[0]=t[1]=t[2]=0;getdeep(x,-1);
47     return t[1]*t[2]*2+t[0]*t[0];
48 }
49 void dfs(int x)
50 {
51     deep[x]=0;vis[x]=true;ans+=calc(x);
52     for(int i=first[x];i;i=e[i].next)
53     {
54         int to=e[i].to;
55         if(vis[to])continue;
56         deep[to]=e[i].w;
57         ans-=calc(to);
58         sum=sz[to];root=0;
59         getroot(to,-1);dfs(root);
60     }
61 }
62 int gcd(int a,int b){return !b?a:gcd(b,a%b);}
63 int main()
64 {
65     n=read();
66     for(int i=1;i<n;i++)
67     {
68         x=read();y=read();w=read()%3;
69         ins(x,y,w);ins(y,x,w);
70     }
71     root=0;sum=n;mx[0]=inf;
72     getroot(1,-1);dfs(root);
73     int g=gcd(ans,n*n);
74     printf("%d/%d\n",ans/g,n*n/g);
75     return 0;
76 }

3.【bzoj2599】[IOI2011]Race

题意:给一棵树,每条边有权。求一条简单路径,权值和等于K,且边的数量最小。

分析:wxx_louisaの博客

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=2e5+5;
 6 const int inf=0x3f3f3f3f;
 7 int n,K,cnt,x,y,w,root,sum,ans,froot;
 8 int first[N],sz[N],deep[N],dis[N],t[N*5];
 9 bool vis[N];
10 struct edge{int to,next,w;}e[N<<1];
11 int read()
12 {
13     int x=0,f=1;char c=getchar();
14     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
15     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
16     return x*f;
17 }
18 void ins(int u,int v,int w){e[++cnt]=(edge){v,first[u],w};first[u]=cnt;}
19 void getroot(int x,int fa)
20 {
21     bool flag=true;sz[x]=1;
22     for(int i=first[x];i;i=e[i].next)
23     {
24         int to=e[i].to;
25         if(to==fa||vis[to])continue;
26         getroot(to,x);
27         sz[x]+=sz[to];
28         if(sz[to]>sum/2)flag=false;
29     }
30     if(sum-sz[x]>sum/2)flag=false;
31     if(flag)root=x,froot=fa;
32 }
33 void getdeep(int x,int fa)
34 {
35     if(dis[x]<=K)ans=min(ans,deep[x]+t[K-dis[x]]);
36     for(int i=first[x];i;i=e[i].next)
37     {
38         int to=e[i].to;
39         if(to==fa||vis[to])continue;
40         dis[to]=dis[x]+e[i].w;
41         deep[to]=deep[x]+1;
42         getdeep(to,x);
43     }
44 }
45 void check(int x,int fa,int flag)
46 {
47     if(dis[x]<=K)
48     {
49         if(flag)t[dis[x]]=min(t[dis[x]],deep[x]);
50         else t[dis[x]]=n;
51     }
52     for(int i=first[x];i;i=e[i].next)
53     {
54         int to=e[i].to;
55         if(to==fa||vis[to])continue;
56         check(to,x,flag);
57     }
58 }
59 void dfs(int x,int s,int fa)
60 {
61     vis[x]=true;dis[x]=deep[x]=0;t[0]=0;
62     for(int i=first[x];i;i=e[i].next)
63     {
64         int to=e[i].to;
65         if(vis[to])continue;
66         deep[to]=1;dis[to]=e[i].w;
67         getdeep(to,x);check(to,x,1);
68     }
69     for(int i=first[x];i;i=e[i].next)
70     {
71         int to=e[i].to;
72         if(vis[to])continue;
73         check(to,x,0);
74     }
75     for(int i=first[x];i;i=e[i].next)
76     {
77         int to=e[i].to;
78         if(vis[to])continue;
79         if(to==fa)sum=s-sz[x];
80         else sum=sz[to];
81         root=0;getroot(to,x);
82         dfs(root,sum,froot);
83     }
84 }
85 int main()
86 {
87     n=read();K=read();
88     for(int i=1;i<=K;i++)t[i]=n;
89     for(int i=1;i<n;i++)
90     {
91         x=read()+1;y=read()+1;w=read();
92         ins(x,y,w);ins(y,x,w);
93     }
94     root=0;sum=n;ans=n;
95     getroot(1,-1);dfs(root,n,froot);
96     if(ans==n)printf("-1\n");
97     else printf("%d\n",ans);
98     return 0;
99 }

4.【bzoj3697】采药人的路径

题意:给定一棵n个点的树,边权只有0或1。一条路径是合法的,要求路径上边权为0和1的边数量相等,且路径中有一个点(不包括起点和终点),满足起点到该点和该点到终点的路径上边权为0和1的边数量也相等。求一共可以选择多少种不同的路径。

分析:CQzhangyuの博客

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define LL long long
 5 using namespace std;
 6 const int N=1e5+5;
 7 const int base=1e5;
 8 const int inf=0x3f3f3f3f;
 9 int n,cnt,x,y,w,sum,root,d;
10 int first[N],sz[N],mx[N],dep[N];
11 int s[N<<1],f[N<<1][2],g[N<<1][2];
12 LL ans;
13 bool vis[N];
14 struct edge{int to,next,w;}e[N<<1];
15 int read()
16 {
17     int x=0,f=1;char c=getchar();
18     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
19     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
20     return x*f;
21 }
22 void ins(int u,int v,int w){e[++cnt]=(edge){v,first[u],w};first[u]=cnt;}
23 void getroot(int x,int fa)
24 {
25     sz[x]=1;mx[x]=0;
26     for(int i=first[x];i;i=e[i].next)
27     {
28         int to=e[i].to;
29         if(to==fa||vis[to])continue;
30         getroot(to,x);
31         sz[x]+=sz[to];
32         mx[x]=max(mx[x],sz[to]);
33     }
34     mx[x]=max(mx[x],sum-sz[x]);
35     if(mx[root]>mx[x])root=x;
36 }
37 void getdeep(int x,int fa)
38 {
39     d=max(d,max(dep[x],-dep[x]));
40     if(s[dep[x]+base])g[dep[x]+base][1]++;
41     else g[dep[x]+base][0]++;
42     s[dep[x]+base]++;
43     for(int i=first[x];i;i=e[i].next)
44     {
45         int to=e[i].to;
46         if(to==fa||vis[to])continue;
47         dep[to]=dep[x]+e[i].w;
48         getdeep(to,x);
49     }
50     s[dep[x]+base]--;
51 }
52 void dfs(int x)
53 {
54     vis[x]=true;int dd=0;
55     for(int i=first[x];i;i=e[i].next)
56     {
57         int to=e[i].to;
58         if(vis[to])continue;
59         dep[to]=e[i].w;d=0;
60         getdeep(to,x);dd=max(dd,d);
61         for(int j=base-d;j<=base+d;j++)
62             ans+=1ll*f[base*2-j][0]*g[j][1]+1ll*f[base*2-j][1]*g[j][0]+1ll*f[base*2-j][1]*g[j][1];
63         ans+=1ll*f[base][0]*g[base][0]+g[base][1];
64         for(int j=base-d;j<=base+d;j++)
65             f[j][0]+=g[j][0],f[j][1]+=g[j][1],g[j][0]=g[j][1]=0;
66     }
67     for(int i=base-dd;i<=base+dd;i++)f[i][0]=f[i][1]=0;
68     for(int i=first[x];i;i=e[i].next)
69     {
70         int to=e[i].to;
71         if(vis[to])continue;
72         root=0;sum=sz[to];
73         getroot(to,x);dfs(root);
74     }
75 }
76 int main()
77 {
78     n=read();
79     for(int i=1;i<n;i++)
80     {
81         x=read();y=read();w=read();
82         w=(w==0)?-1:1;ins(x,y,w);ins(y,x,w);
83     }
84     root=0;sum=n;mx[0]=inf;
85     getroot(1,-1);dfs(root);
86     printf("%lld\n",ans);
87     return 0;
88 }

5.【Codecraft-18 and Codeforces Round #458】E. Palindromes in a Tree

题意:给定n个点的树,每个点有一个a~t的字母,一条路径回文当且仅当路径上的字母的某一个排列回文,求经过每个点的回文路径数。

分析:点分治+状压

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define LL long long
 5 using namespace std;
 6 const int N=2e5+5;
 7 const int inf=0x3f3f3f3f;
 8 int n,cnt,x,y,root,sum;
 9 int id[N],first[N],sz[N],mx[N];
10 bool vis[N];
11 LL ans[N],mp[(1<<20)+5];
12 char s[N];
13 struct edge{int to,next;}e[N*2];
14 int read()
15 {
16     int x=0,f=1;char c=getchar();
17     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
18     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
19     return x*f;
20 }
21 int max(int a,int b){return a>b?a:b;}
22 void ins(int u,int v){e[++cnt]=(edge){v,first[u]};first[u]=cnt;}
23 void getroot(int x,int fa)
24 {
25     sz[x]=1;mx[x]=0;
26     for(int i=first[x];i;i=e[i].next)
27     {
28         int to=e[i].to;
29         if(to==fa||vis[to])continue;
30         getroot(to,x);
31         sz[x]+=sz[to];
32         mx[x]=max(mx[x],sz[to]);
33     }
34     mx[x]=max(mx[x],sum-sz[x]);
35     if(mx[root]>mx[x])root=x;
36 }
37 void getway(int x,int fa,int val,int k)
38 {
39     val^=id[x];mp[val]+=k;
40     for(int i=first[x];i;i=e[i].next)
41     {
42         int to=e[i].to;
43         if(to==fa||vis[to])continue;
44         getway(to,x,val,k);
45     }
46 }
47 LL check(int x,int fa,int val)
48 {
49     val^=id[x];LL num=mp[val];
50     for(int i=0;i<20;i++)num+=mp[(1<<i)^val];
51     for(int i=first[x];i;i=e[i].next)
52     {
53         int to=e[i].to;
54         if(to==fa||vis[to])continue;
55         num+=check(to,x,val);
56     }
57     ans[x]+=num;return num;
58 }
59 void solve(int x)
60 {
61     vis[x]=true;getway(x,-1,0,1);
62     LL num=mp[0];
63     for(int i=0;i<20;i++)num+=mp[1<<i];
64     for(int i=first[x];i;i=e[i].next)
65     {
66         int to=e[i].to;
67         if(vis[to])continue;
68         getway(to,x,id[x],-1);
69         num+=check(to,x,0);
70         getway(to,x,id[x],1);
71     }
72     ans[x]+=num/2;getway(x,-1,0,-1);
73     for(int i=first[x];i;i=e[i].next)
74     {
75         int to=e[i].to;
76         if(vis[to])continue;
77         sum=sz[to];root=0;
78         getroot(to,-1);solve(root);
79     }
80 }
81 int main()
82 {
83     n=read();
84     for(int i=1;i<n;i++)x=read(),y=read(),ins(x,y),ins(y,x);
85     scanf("%s",s+1);
86     for(int i=1;i<=n;i++)id[i]=1<<(s[i]-‘a‘);
87     sum=n;mx[0]=inf;getroot(1,-1);solve(root);
88     for(int i=1;i<=n;i++)printf("%lld ",ans[i]+1);
89     return 0;
90 }

【Link-Cut Tree】

〖相关资料〗

《动态树之link-cut tree》

〖模板代码〗

 1 struct LCT
 2 {
 3     int c[N][2],fa[N],sum[N],val[N];
 4     bool rev[N];
 5     bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
 6     void update(int x){sum[x]=sum[c[x][0]]+sum[c[x][1]]+val[x];}
 7     void flip(int x){swap(c[x][0],c[x][1]);rev[x]^=1;}
 8     void down(int x){if(rev[x])flip(c[x][0]),flip(c[x][1]),rev[x]=0;}
 9     void rotate(int x)
10     {
11         int y=fa[x],z=fa[y],l,r;
12         if(c[y][0]==x)l=0;else l=1;r=l^1;
13         if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
14         fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
15         c[y][l]=c[x][r];c[x][r]=y;
16         update(y);update(x);
17     }
18     void relax(int x){if(!isroot(x))relax(fa[x]);down(x);}
19     void splay(int x)
20     {
21         relax(x);
22         while(!isroot(x))
23         {
24             int y=fa[x],z=fa[y];
25             if(!isroot(y))
26             {
27                 if((c[y][0]==x)^(c[z][0]==y))rotate(x);
28                 else rotate(y);
29             }
30             rotate(x);
31         }
32     }
33     void access(int x){int t=0;while(x)splay(x),c[x][1]=t,update(x),t=x,x=fa[x];}
34     void makeroot(int x){access(x);splay(x);flip(x);}
35     bool connected(int x,int y)
36     {
37         if(x==y)return true;
38         makeroot(x);access(y);splay(y);return fa[x]!=0;
39     }
40     void modify(int x,int v){splay(x);val[x]=v;update(x);}
41     void link(int x,int y){makeroot(x);fa[x]=y;}
42     void cut(int x,int y){makeroot(x);access(y);splay(y);c[y][0]=fa[x]=0;update(y);}
43     int query(int x,int y){makeroot(x);access(y);splay(y);return sum[y];}
44 }T;

〖相关题目〗

1.【bzoj3282】Tree

题意:给定n个点以及每个点的权值,处理m个操作。0:询问从x到y的路径上的点的权值的xor和。保证x到y是联通的。1:连接x到y,若x到y已经联通则无需连接。2:删除边(x,y),不保证边(x,y)存在。3:将点X上的权值变成Y。

分析:Link-Cut Tree裸题

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define LL long long
 5 using namespace std;
 6 const int N=3e5+5;
 7 int n,m,op,x,y;
 8 int read()
 9 {
10     int x=0,f=1;char c=getchar();
11     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
12     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
13     return x*f;
14 }
15 struct LCT
16 {
17     int c[N][2],fa[N],sum[N],val[N];
18     bool rev[N];
19     bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
20     void update(int x){sum[x]=sum[c[x][0]]^sum[c[x][1]]^val[x];}
21     void flip(int x){swap(c[x][0],c[x][1]);rev[x]^=1;}
22     void down(int x){if(rev[x])flip(c[x][0]),flip(c[x][1]),rev[x]=0;}
23     void rotate(int x)
24     {
25         int y=fa[x],z=fa[y],l,r;
26         if(c[y][0]==x)l=0;else l=1;r=l^1;
27         if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
28         fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
29         c[y][l]=c[x][r];c[x][r]=y;
30         update(y);update(x);
31     }
32     void relax(int x){if(!isroot(x))relax(fa[x]);down(x);}
33     void splay(int x)
34     {
35         relax(x);
36         while(!isroot(x))
37         {
38             int y=fa[x],z=fa[y];
39             if(!isroot(y))
40             {
41                 if((c[y][0]==x)^(c[z][0]==y))rotate(x);
42                 else rotate(y);
43             }
44             rotate(x);
45         }
46     }
47     void access(int x){int t=0;while(x){splay(x);c[x][1]=t;update(x);t=x;x=fa[x];}}
48     void makeroot(int x){access(x);splay(x);flip(x);}
49     void modify(int x,int v){splay(x);val[x]=v;update(x);}
50     void link(int x,int y){makeroot(x);fa[x]=y;}
51     void cut(int x,int y){makeroot(x);access(y);splay(y);c[y][0]=fa[x]=0;update(y);}
52     int query(int x,int y){makeroot(x);access(y);splay(y);return sum[y];}
53 }T;
54 int main()
55 {
56     n=read();m=read();
57     for(int i=1;i<=n;i++)T.val[i]=T.sum[i]=read();
58     while(m--)
59     {
60         op=read();x=read();y=read();
61         if(op==0)printf("%d\n",T.query(x,y));
62         if(op==1)T.link(x,y);
63         if(op==2)T.cut(x,y);
64         if(op==3)T.modify(x,y);
65     }
66     return 0;
67 }

2.【bzoj1180】[CROATIAN2009]OTOCI

题意:给定n个点以及每个点的权值,处理m个操作。详见题目。

分析:Link-Cut Tree裸题

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define LL long long
 5 using namespace std;
 6 const int N=3e4+5;
 7 int n,m,x,y;
 8 char s[10];
 9 int read()
10 {
11     int x=0,f=1;char c=getchar();
12     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
13     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
14     return x*f;
15 }
16 struct LCT
17 {
18     int c[N][2],fa[N],sum[N],val[N];
19     bool rev[N];
20     bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
21     void update(int x){sum[x]=sum[c[x][0]]+sum[c[x][1]]+val[x];}
22     void flip(int x){swap(c[x][0],c[x][1]);rev[x]^=1;}
23     void down(int x){if(rev[x])flip(c[x][0]),flip(c[x][1]),rev[x]=0;}
24     void rotate(int x)
25     {
26         int y=fa[x],z=fa[y],l,r;
27         if(c[y][0]==x)l=0;else l=1;r=l^1;
28         if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
29         fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
30         c[y][l]=c[x][r];c[x][r]=y;
31         update(y);update(x);
32     }
33     void relax(int x){if(!isroot(x))relax(fa[x]);down(x);}
34     void splay(int x)
35     {
36         relax(x);
37         while(!isroot(x))
38         {
39             int y=fa[x],z=fa[y];
40             if(!isroot(y))
41             {
42                 if((c[y][0]==x)^(c[z][0]==y))rotate(x);
43                 else rotate(y);
44             }
45             rotate(x);
46         }
47     }
48     void access(int x){int t=0;while(x)splay(x),c[x][1]=t,update(x),t=x,x=fa[x];}
49     void makeroot(int x){access(x);splay(x);flip(x);}
50     bool connected(int x,int y)
51     {
52         if(x==y)return true;
53         makeroot(x);access(y);splay(y);return fa[x]!=0;
54     }
55     void modify(int x,int v){splay(x);val[x]=v;update(x);}
56     void link(int x,int y){makeroot(x);fa[x]=y;}
57     void cut(int x,int y){makeroot(x);access(y);splay(y);c[y][0]=fa[x]=0;update(y);}
58     int query(int x,int y){makeroot(x);access(y);splay(y);return sum[y];}
59 }T;
60 int main()
61 {
62     n=read();
63     for(int i=1;i<=n;i++)T.sum[i]=T.val[i]=read();
64     m=read();
65     while(m--)
66     {
67         scanf("%s",s);x=read();y=read();
68         if(s[0]==‘b‘)
69         {
70             if(T.connected(x,y))printf("no\n");
71             else printf("yes\n"),T.link(x,y);
72         }
73         if(s[0]==‘p‘)T.modify(x,y);
74         if(s[0]==‘e‘)
75         {
76             if(T.connected(x,y))printf("%d\n",T.query(x,y));
77             else printf("impossible\n");
78         }
79     }
80     return 0;
81 }

3.【bzoj2759】一个动态树好题

题意:有n个x[1..n]和n个等式组成的同余方程组:x[i]=k[i]*x[p[i]]+b[i] mod 10007。要应付Q个事务,每个是两种情况之一:一、询问当前x[a]的解,无解输出-1,多解输出-2,否则输出x[a];二、修改一个等式 C a k[a] p[a] b[a]。

分析:PoPoQQQの博客

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define LL long long
  5 using namespace std;
  6 const int N=3e4+5;
  7 const int mod=1e4+7;
  8 int n,m,id,k,p,b;
  9 char op[2];
 10 int read()
 11 {
 12     int x=0,f=1;char c=getchar();
 13     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
 14     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
 15     return x*f;
 16 }
 17 struct data
 18 {
 19     int k,b;
 20     data(){k=1;b=0;}
 21     int calc(int x){return (k*x+b)%mod;}
 22 };
 23 data operator + (data a,data b)
 24 {
 25     data c;
 26     c.k=a.k*b.k%mod;
 27     c.b=(b.k*a.b%mod+b.b)%mod;
 28     return c;
 29 }
 30 int exgcd(int a,int b,int& x,int& y)
 31 {
 32     if(!b){x=1;y=0;return a;}
 33     int ans=exgcd(b,a%b,x,y);
 34     int tmp=x;x=y;y=tmp-a/b*y;
 35     return ans;
 36 }
 37 struct LCT
 38 {
 39     int c[N][2],fa[N],sfa[N];
 40     bool ins[N],vis[N];
 41     data val[N],sum[N];
 42     bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
 43     void update(int x){sum[x]=sum[c[x][0]]+val[x]+sum[c[x][1]];}
 44     void dfs(int x)
 45     {
 46         ins[x]=vis[x]=true;int to=fa[x];
 47         if(ins[to])fa[x]=0,sfa[x]=to;
 48         if(!vis[to])dfs(to);ins[x]=false;
 49     }
 50     void init(int n)
 51     {
 52         int k,b;
 53         for(int i=1;i<=n;i++)
 54         {
 55             k=read();fa[i]=read();b=read();
 56             data tmp;tmp.k=k;tmp.b=b;
 57             val[i]=sum[i]=tmp;
 58         }
 59         for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
 60     }
 61     void rotate(int x)
 62     {
 63         int y=fa[x],z=fa[y],l,r;
 64         if(c[y][0]==x)l=0;else l=1;r=l^1;
 65         if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
 66         fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
 67         c[y][l]=c[x][r];c[x][r]=y;
 68         update(y);update(x);
 69     }
 70     void splay(int x)
 71     {
 72         while(!isroot(x))
 73         {
 74             int y=fa[x],z=fa[y];
 75             if(!isroot(y))
 76             {
 77                 if((c[y][0]==x)^(c[z][0]==y))rotate(x);
 78                 else rotate(y);
 79             }
 80             rotate(x);
 81         }
 82     }
 83     void access(int x){int t=0;while(x)splay(x),c[x][1]=t,update(x),t=x,x=fa[x];}
 84     int findroot(int x)
 85     {
 86         access(x);splay(x);
 87         int t=x;while(c[t][0])t=c[t][0];
 88         splay(t);return t;
 89     }
 90     int query(int x)
 91     {
 92         access(x);splay(x);data v1=sum[x];
 93         int rt=findroot(x),sf=sfa[rt];
 94         access(sf);splay(sf);data v2=sum[sf];
 95         if(v2.k==0)return v1.calc(v2.b);
 96         if(v2.k==1)return v2.b?-1:-2;
 97         int xx,yy;exgcd(v2.k-1,mod,xx,yy);
 98 //        return v1.calc((mod-xx)%mod*v2.b%mod);
 99         return v1.calc((xx%mod+mod)%mod*(((mod-v2.b)%mod+mod)%mod)%mod);
100     }
101     void cut(int x){access(x);splay(x);fa[c[x][0]]=0;c[x][0]=0;update(x);}
102     void link(int x,int f){access(x);splay(x);fa[x]=f;}
103     bool oncircle(int x,int rt)
104     {
105         int sf=sfa[rt];
106         if(x==sf)return true;
107         access(sf);splay(sf);splay(x);
108         return !isroot(sf);
109     }
110     void change(int x,int f,int k,int b)
111     {
112         access(x);splay(x);
113         data tmp;tmp.k=k;tmp.b=b;
114         val[x]=tmp;update(x);
115         int rt=findroot(x);
116         if(x==rt)
117         {
118             int rf=findroot(f);
119             if(rt==rf)sfa[x]=f;
120             else sfa[x]=0,link(x,f);
121         }
122         else
123         {
124             if(oncircle(x,rt))
125             {
126                 cut(x);link(rt,sfa[rt]);sfa[rt]=0;
127                 int rf=findroot(f);
128                 if(x==rf)sfa[x]=f;
129                 else link(x,f);
130             }
131             else
132             {
133                 cut(x);int rf=findroot(f);
134                 if(x==rf)sfa[x]=f;
135                 else link(x,f);
136             }
137         }
138     }
139 }lct;
140 int main()
141 {
142     n=read();lct.init(n);
143     m=read();
144     while(m--)
145     {
146         scanf("%s",op);id=read();
147         if(op[0]==‘A‘)printf("%d\n",lct.query(id));
148         else k=read(),p=read(),b=read(),lct.change(id,p,k,b);
149     }
150     return 0;
151 }

4.【bzoj4530】[Bjoi2014]大融合

题意:给定n个点,逐条加边,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量。随着边的添加,动态的回答对于某些边的负载的询问。

分析:GXZlegendの博客

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define LL long long
 5 using namespace std;
 6 const int N=1e5+5;
 7 int n,m,x,y;
 8 char op[2];
 9 int read()
10 {
11     int x=0,f=1;char c=getchar();
12     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
13     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
14     return x*f;
15 }
16 struct LCT
17 {
18     int c[N][2],fa[N],sum[N],val[N];
19     bool rev[N];
20     bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
21     void update(int x){sum[x]=sum[c[x][0]]+sum[c[x][1]]+val[x]+1;}
22     void flip(int x){swap(c[x][0],c[x][1]);rev[x]^=1;}
23     void down(int x){if(rev[x])flip(c[x][0]),flip(c[x][1]),rev[x]=0;}
24     void rotate(int x)
25     {
26         int y=fa[x],z=fa[y],l,r;
27         if(c[y][0]==x)l=0;else l=1;r=l^1;
28         if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
29         fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
30         c[y][l]=c[x][r];c[x][r]=y;
31         update(y);update(x);
32     }
33     void relax(int x){if(!isroot(x))relax(fa[x]);down(x);}
34     void splay(int x)
35     {
36         relax(x);
37         while(!isroot(x))
38         {
39             int y=fa[x],z=fa[y];
40             if(!isroot(y))
41             {
42                 if((c[y][0]==x)^(c[z][0]==y))rotate(x);
43                 else rotate(y);
44             }
45             rotate(x);
46         }
47     }
48     void access(int x)
49     {
50         int t=0;
51         while(x)
52         {
53             splay(x);val[x]+=sum[c[x][1]]-sum[t];
54             c[x][1]=t;update(x);t=x;x=fa[x];
55         }
56     }
57     void makeroot(int x){access(x);splay(x);flip(x);}
58     void link(int x,int y)
59     {
60         makeroot(x);makeroot(y);
61         fa[x]=y;val[y]+=sum[x];update(y);
62     }
63 }T;
64 int main()
65 {
66     n=read();m=read();
67     for(int i=1;i<=n;i++)T.sum[i]=1;
68     while(m--)
69     {
70         scanf("%s",op);
71         x=read();y=read();
72         if(op[0]==‘A‘)T.link(x,y);
73         else
74         {
75             T.makeroot(x);T.makeroot(y);
76             printf("%lld\n",1ll*T.sum[x]*(T.sum[y]-T.sum[x]));
77         }
78     }
79     return 0;
80 }

5.【bzoj 3779】重组病毒

题意:见原题。

分析:Zsnuoの博客

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #define LL long long
  5 #define lc(x) x<<1
  6 #define rc(x) x<<1|1
  7 using namespace std;
  8 const int N=1e5+5;
  9 int n,m,x,y,cnt,dfn,rt=1,first[N];
 10 int deep[N],in[N],out[N],fa[N][18];
 11 char op[15];
 12 int read()
 13 {
 14     int x=0,f=1;char c=getchar();
 15     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
 16     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
 17     return x*f;
 18 }
 19 struct edge{int to,next;}e[N<<1];
 20 void ins(int u,int v){e[++cnt]=(edge){v,first[u]};first[u]=cnt;}
 21 struct SGT
 22 {
 23     int l[N*4],r[N*4];
 24     LL sum[N*4],tag[N*4];
 25     void build(int x,int L,int R)
 26     {
 27         l[x]=L;r[x]=R;if(L==R)return;
 28         int mid=(L+R)>>1;
 29         build(lc(x),L,mid);build(rc(x),mid+1,R);
 30     }
 31     void up(int x){sum[x]=sum[lc(x)]+sum[rc(x)];}
 32     void qadd(int x,LL w){tag[x]+=w;sum[x]+=w*(r[x]-l[x]+1);}
 33     void down(int x)
 34     {
 35         if(!tag[x])return;
 36         qadd(lc(x),tag[x]);qadd(rc(x),tag[x]);
 37         tag[x]=0;
 38     }
 39     void add(int x,int L,int R,LL w)
 40     {
 41         if(L<=l[x]&&r[x]<=R){qadd(x,w);return;}
 42         down(x);int mid=(l[x]+r[x])>>1;
 43         if(L<=mid)add(lc(x),L,R,w);
 44         if(R>mid)add(rc(x),L,R,w);
 45         up(x);
 46     }
 47     LL query(int x,int L,int R)
 48     {
 49         if(L<=l[x]&&r[x]<=R)return sum[x];
 50         down(x);LL ans=0;
 51         int mid=(l[x]+r[x])>>1;
 52         if(L<=mid)ans+=query(lc(x),L,R);
 53         if(R>mid)ans+=query(rc(x),L,R);
 54         return ans;
 55     }
 56 }sgt;
 57 int find(int x,int y)
 58 {
 59     int d=deep[y]-deep[x]-1;
 60     for(int i=16;i>=0;i--)
 61         if(d&(1<<i))y=fa[y][i];
 62     return y;
 63 }
 64 void addson(int x,LL w)
 65 {
 66     if(x==rt)sgt.add(1,1,n,w);
 67     else if(in[rt]>=in[x]&&out[rt]<=out[x])
 68     {
 69         int t=find(x,rt);
 70         if(in[t]>1)sgt.add(1,1,in[t]-1,w);
 71         if(out[t]<n)sgt.add(1,out[t]+1,n,w);
 72     }
 73     else sgt.add(1,in[x],out[x],w);
 74 }
 75 struct LCT
 76 {
 77     int c[N][2],fa[N],in[N],out[N];
 78     bool rev[N];
 79     bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
 80     void flip(int x){swap(c[x][0],c[x][1]);rev[x]^=1;}
 81     void down(int x){if(rev[x])flip(c[x][0]),flip(c[x][1]),rev[x]=0;}
 82     void rotate(int x)
 83     {
 84         int y=fa[x],z=fa[y],l,r;
 85         if(c[y][0]==x)l=0;else l=1;r=l^1;
 86         if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
 87         fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
 88         c[y][l]=c[x][r];c[x][r]=y;
 89     }
 90     void relax(int x){if(!isroot(x))relax(fa[x]);down(x);}
 91     void splay(int x)
 92     {
 93         relax(x);
 94         while(!isroot(x))
 95         {
 96             int y=fa[x],z=fa[y];
 97             if(!isroot(y))
 98             {
 99                 if((c[y][0]==x)^(c[z][0]==y))rotate(x);
100                 else rotate(y);
101             }
102             rotate(x);
103         }
104     }
105     int top(int x){down(x);while(c[x][0])x=c[x][0],down(x);return x;}
106     void access(int x)
107     {
108         int t=0;
109         while(x)
110         {
111             splay(x);
112             if(c[x][1])addson(top(c[x][1]),1);
113             if(t)addson(top(t),-1);
114             c[x][1]=t;t=x;x=fa[x];
115         }
116     }
117     void makeroot(int x){splay(x);rt=x;flip(x);}
118 }lct;
119 void dfs(int x)
120 {
121     in[x]=++dfn;
122     sgt.add(1,in[x],in[x],deep[x]);
123     for(int i=1;(1<<i)<=deep[x];i++)
124         fa[x][i]=fa[fa[x][i-1]][i-1];
125     for(int i=first[x];i;i=e[i].next)
126     {
127         int to=e[i].to;
128         if(to==fa[x][0])continue;
129         fa[to][0]=lct.fa[to]=x;
130         deep[to]=deep[x]+1;dfs(to);
131     }
132     out[x]=dfn;
133 }
134 double request(int x)
135 {
136     if(x==rt)return 1.0*sgt.query(1,1,n)/n;
137     if(in[rt]>=in[x]&&out[rt]<=out[x])
138     {
139         int t=find(x,rt);LL sum=0;
140         if(in[t]>1)sum+=sgt.query(1,1,in[t]-1);
141         if(out[t]<n)sum+=sgt.query(1,out[t]+1,n);
142         return 1.0*sum/(n-(out[t]-in[t]+1));
143     }
144     return 1.0*sgt.query(1,in[x],out[x])/(out[x]-in[x]+1);
145 }
146 int main()
147 {
148     n=read();m=read();
149     for(int i=1;i<n;i++)x=read(),y=read(),ins(x,y),ins(y,x);
150     sgt.build(1,1,n);deep[1]=1;dfs(1);
151     while(m--)
152     {
153         scanf("%s",op);x=read();
154         if(op[2]==‘Q‘)printf("%.10lf\n",request(x));
155         else
156         {
157             lct.access(x);
158             if(op[2]==‘C‘)lct.makeroot(x);
159         }
160     }
161     return 0;
162 }

【虚树】

〖相关资料〗

《虚树详解+例子分析+模板》

〖相关题目〗

1.【bzoj2286】[Sdoi2011]消耗战

题意:给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价。

分析:ONION_CYCの博客

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define LL long long
 5 using namespace std;
 6 const int N=250005;
 7 const int inf=0x3f3f3f3f;
 8 int n,m,x,y,w,tim,cnt,cntv;
 9 int a[N<<1],first[N],firstv[N],st[N];
10 int dfn[N],out[N],deep[N],fa[N][20];
11 LL val[N];
12 bool f[N];
13 struct edge{int to,next,w;}e[N<<1],ev[N<<1];
14 int read()
15 {
16     int x=0,f=1;char c=getchar();
17     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
18     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
19     return x*f;
20 }
21 void ins(int u,int v,int w){e[++cnt]=(edge){v,first[u],w};first[u]=cnt;}
22 void insv(int u,int v){ev[++cntv]=(edge){v,firstv[u],0};firstv[u]=cntv;}
23 void dfs(int x)
24 {
25     dfn[x]=++tim;
26     for(int i=1;(1<<i)<=deep[x];i++)
27         fa[x][i]=fa[fa[x][i-1]][i-1];
28     for(int i=first[x];i;i=e[i].next)
29     {
30         int to=e[i].to;
31         if(to==fa[x][0])continue;
32         fa[to][0]=x;
33         deep[to]=deep[x]+1;
34         val[to]=min(val[x],1ll*e[i].w);
35         dfs(to);
36     }
37     out[x]=tim;
38 }
39 int lca(int x,int y)
40 {
41     if(deep[x]<deep[y])swap(x,y);
42     int d=deep[x]-deep[y];
43     for(int i=0;(1<<i)<=d;i++)
44         if((1<<i)&d)x=fa[x][i];
45     if(x==y)return x;
46     for(int i=18;i>=0;i--)
47         if((1<<i)<=deep[x]&&fa[x][i]!=fa[y][i])
48             x=fa[x][i],y=fa[y][i];
49     return fa[x][0];
50 }
51 bool cmp(int a,int b){return dfn[a]<dfn[b];}
52 bool check(int x,int y){return dfn[x]<=out[y];}
53 LL dp(int x)
54 {
55     if(f[x])return val[x];LL sum=0;
56     for(int i=firstv[x];i;i=ev[i].next)sum+=dp(ev[i].to);
57     return min(val[x],sum);
58 }
59 void work()
60 {
61     int k=read(),tmp=k;
62     for(int i=1;i<=k;i++)a[i]=read(),f[a[i]]=true;
63     sort(a+1,a+k+1,cmp);
64     for(int i=1;i<tmp;i++)a[++k]=lca(a[i],a[i+1]);
65     sort(a+1,a+k+1,cmp);
66     k=unique(a+1,a+k+1)-a-1;
67     for(int i=1;i<=k;i++)firstv[a[i]]=0;
68     cntv=0;int top=0;
69     for(int i=1;i<=k;i++)
70     {
71         while(top&&!check(a[i],st[top]))top--;
72         if(top)insv(st[top],a[i]);
73         st[++top]=a[i];
74     }
75     printf("%lld\n",dp(a[1]));
76     for(int i=1;i<=k;i++)f[a[i]]=false;
77 }
78 int main()
79 {
80     n=read();
81     for(int i=1;i<n;i++)
82     {
83         x=read();y=read();w=read();
84         ins(x,y,w);ins(y,x,w);
85     }
86     val[1]=1e16;dfs(1);
87     m=read();
88     while(m--)work();
89     return 0;
90 }

2.【bzoj3572】[Hnoi2014]世界树

题意:给定n个点的树,m次询问,每次给定ki个特殊点,一个点会被最近的特殊点控制,询问每个特殊点控制多少点。

分析:hzwerの博客

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #define LL long long
  5 using namespace std;
  6 const int N=300005;
  7 int n,m,x,y,cnt,tim,top;
  8 int a[N],b[N],bel[N],first[N],st[N],rem[N],f[N];
  9 int size[N],dfn[N],out[N],deep[N],fa[N][20];
 10 struct edge{int to,next;}e[N<<1];
 11 int read()
 12 {
 13     int x=0,f=1;char c=getchar();
 14     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
 15     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
 16     return x*f;
 17 }
 18 void ins(int u,int v){e[++cnt]=(edge){v,first[u]};first[u]=cnt;}
 19 void dfs(int x)
 20 {
 21     dfn[x]=++tim;size[x]=1;
 22     for(int i=1;(1<<i)<=deep[x];i++)
 23         fa[x][i]=fa[fa[x][i-1]][i-1];
 24     for(int i=first[x];i;i=e[i].next)
 25     {
 26         int to=e[i].to;
 27         if(to==fa[x][0])continue;
 28         deep[to]=deep[x]+1;
 29         fa[to][0]=x;dfs(to);
 30         size[x]+=size[to];
 31     }
 32     out[x]=tim;
 33 }
 34 int lca(int x,int y)
 35 {
 36     if(deep[x]<deep[y])swap(x,y);
 37     int d=deep[x]-deep[y];
 38     for(int i=0;(1<<i)<=d;i++)
 39         if((1<<i)&d)x=fa[x][i];
 40     if(x==y)return x;
 41     for(int i=18;i>=0;i--)
 42         if((1<<i)<=deep[x]&&fa[x][i]!=fa[y][i])
 43             x=fa[x][i],y=fa[y][i];
 44     return fa[x][0];
 45 }
 46 bool cmp(int a,int b){return dfn[a]<dfn[b];}
 47 int dis(int a,int b){return deep[a]+deep[b]-2*deep[lca(a,b)];}
 48 bool check(int x,int y){return dfn[x]<=out[y];}
 49 void dfs1(int x)
 50 {
 51     rem[x]=size[x];
 52     for(int i=first[x];i;i=e[i].next)
 53     {
 54         int to=e[i].to;dfs1(to);
 55         if(!bel[to])continue;
 56         int d1=dis(x,bel[to]),d2=dis(x,bel[x]);
 57         if(!bel[x]||d1<d2||(d1==d2&&bel[to]<bel[x]))bel[x]=bel[to];
 58     }
 59 }
 60 void dfs2(int x)
 61 {
 62     for(int i=first[x];i;i=e[i].next)
 63     {
 64         int to=e[i].to;
 65         int d1=dis(to,bel[x]),d2=dis(to,bel[to]);
 66         if(!bel[to]||d1<d2||(d1==d2&&bel[x]<bel[to]))bel[to]=bel[x];
 67         dfs2(to);
 68     }
 69 }
 70 void solve(int a,int b)
 71 {
 72     int x=b,mid=b;
 73     for(int i=18;i>=0;i--)
 74         if(deep[fa[x][i]]>deep[a])x=fa[x][i];
 75     rem[a]-=size[x];
 76     if(bel[a]==bel[b])
 77     {
 78         f[bel[a]]+=size[x]-size[b];
 79         return;
 80     }
 81     for(int i=18;i>=0;i--)
 82     {
 83         int y=fa[mid][i];
 84         if(deep[y]<=deep[a])continue;
 85         int d1=dis(bel[a],y),d2=dis(bel[b],y);
 86         if(d2<d1||(d1==d2&&bel[b]<bel[a]))mid=y;
 87     }
 88     f[bel[a]]+=size[x]-size[mid];
 89     f[bel[b]]+=size[mid]-size[b];
 90 }
 91 void work()
 92 {
 93     int k=read(),tmp=k;
 94     for(int i=1;i<=k;i++)a[i]=b[i]=read();
 95     for(int i=1;i<=k;i++)bel[a[i]]=a[i];
 96     sort(a+1,a+k+1,cmp);
 97     for(int i=1;i<tmp;i++)a[++k]=lca(a[i],a[i+1]);
 98     a[++k]=1;sort(a+1,a+k+1,cmp);
 99     k=unique(a+1,a+k+1)-a-1;
100     cnt=top=0;
101     for(int i=1;i<=k;i++)first[a[i]]=0;
102     for(int i=1;i<=k;i++)
103     {
104         while(top&&!check(a[i],st[top]))top--;
105         if(top)ins(st[top],a[i]);
106         st[++top]=a[i];
107     }
108     dfs1(1);dfs2(1);
109     for(int i=1;i<=k;i++)
110         for(int j=first[a[i]];j;j=e[j].next)
111             solve(a[i],e[j].to);
112     for(int i=1;i<=k;i++)f[bel[a[i]]]+=rem[a[i]];
113     for(int i=1;i<=tmp;i++)printf("%d ",f[b[i]]);
114     printf("\n");
115     for(int i=1;i<=k;i++)f[a[i]]=bel[a[i]]=0;
116 }
117 int main()
118 {
119     n=read();
120     for(int i=1;i<n;i++)
121     {
122         x=read();y=read();
123         ins(x,y);ins(y,x);
124     }
125     dfs(1);m=read();
126     while(m--)work();
127     return 0;
128 }

原文地址:https://www.cnblogs.com/zsnuo/p/8308638.html

时间: 2024-10-12 01:21:27

【算法总结】树相关的相关文章

算法14---B树

算法14---B树 更详细的讲解见http://www.xuebuyuan.com/509072.html 一棵m阶的B 树 (m叉树)的特性,如下: (1)树中每个结点含有最多含有个孩子,即m满足:ceil(m/2)-1<=n<=m-1. (2)除根结点和叶子结点外,其它每个结点至少有[ceil(m / 2)]个孩子(其中ceil(x)是一个取上限的函数): (3)若根结点不是叶子结点,则至少有2个孩子(特殊情况:没有孩子的根结点,即根结点为叶子结点,整棵树只有一个根节点): 1.1.插入(

【模拟题(63550802...)】解题报告【贪心】【拓扑排序】【找规律】【树相关】

目录: 1.A[树相关]    2.B[找规律]    3.C[贪心][拓扑排序] A. 描述(A 输入文件 : A.input 输出文件 : A.output)一个城市的构成是一颗n 个节点的树(2 ≤ n ≤ 200), 现在需要在树中找出两条不相交的路径(即两条路径不能有重边也不能有重点),使得路径的长度的乘积最大.输入描述第一行一个数n 表示这个城市一共有 n 个节点.接下来 n-1 行,每行两个数ai 和bi (1 ≤ ai,bi ≤ n ),分别表示从ai 到bi,有一条边,每条边的

python数据结构与算法 36 树的基本概念

树 学习目标 理解什么是树及使用方法 学会使用树实现映射 用列表实现树 用类和引用实现树 用递归实现树 用堆实现优先队列 树的例子 前面我们学习过栈和队列这类线性数据结构,并且体验过递归,现在我们学习另一种通用数据结构,叫做树.树在计算机科学中应用广泛,象操作系统.图形学.数据库系统.网络等都要用到树.树和他们在自然界中的表哥--植物树--非常相似,树也有根,有分枝,有叶子.不同之处是,数据结构的树,根在顶上,而叶子在底部. 在开始学习之前,我们来研究几个普通的例子.第一个是生物学上的分级树.图

算法学习 - 树的一些解释

树的解释 树是ADT里面很经典的数据结构了,应用太多了,相对于链表的线性访问时间,O(n).树的大部分操作的平均运行时间都是为O(logN). - 树的概念 树有几种方式定义,一种是递归,若树不为空,则一棵树是由根(root)的节点r和0个或者多个非空树组成.N个节点的树,有N-1个边.没有儿子的节点称为叶子(leaf). 对于任意节点N(i),它的深度为从根节点到N(i)的唯一路径长度.如果存在N(1)到N(2)的路径,那么N(1)是N(2)的祖先.如果N(1)不等于N(2),那么就称为真祖先

python数据结构与算法 37 树的实现

树的实现 记住上一节树的定义,在定义的基础上,我们用以下的函数创建并操作二叉树: BinaryTree() 创建一个二叉树实例 getLeftChild() 返回节点的左孩子 getRightChild() 返回节点的右孩子 setRootVal(val) 把val变量值赋给当前节点 getRootVal() 返回当前节点对象. insertLeft(val) 创建一个新二叉树作为当前节点的左孩子 insertRight(val) 创建一个新二叉树作为当前节点的右孩子. 实现树的关键点是合适的存

java数据结构与算法之树基本概念及二叉树(BinaryTree)的设计与实现

[版权申明]未经博主同意,不允许转载!(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/53727333 出自[zejian的博客] 关联文章: java数据结构与算法之顺序表与链表设计与实现分析 java数据结构与算法之双链表设计与实现 java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制) java数据结构与算法之栈(Stack)设

C#编程结构和算法之树

本文讲解的是C#编程结构和算法之树. 首先,在win下,进入命令行,输入tree,它会以树的形式返回当前文件夹下的所有子文件夹及文件. 如上图,就是一个树. 就像一棵被颠倒过来的苹果树,每一个元素称之为节点,如图,A就是这棵树的老大了,称为根(root),如果某个节点有元素的话,这个节点相对于它的子节点为根,这棵树相对于A来说,是它的子树,例如,树D是A的子树. 对于没有子节点的节点,称之为叶节点. 这些树的根都被来自跟的每一条有向的边所连接.例如树E被来自根A的有向边TAE所连接.树J被来自根

《啊哈算法》——树

这篇文章开始讨论有关“树”的一些简单的概念和算法. 树是一种基本的数据结构,之所以叫树是因为来自于仿生——树枝分叉的结构或者树根分叉的结构,它非常好的表示出了各个节点之间的逻辑关系,它也是图论当中一个很重要的结构.从它的名字的角度,我们发现很多科学思维的生发都是源于对自然的敏锐的观察的,这给科研人员提供了一个非常好的方法. 我们观察自然界的树结构,很容易发现没有哪棵树的两个枝叶长到了一起,而抽象化的树结构也是这样,从根节点出发,一条路径越走越深,是不会有回路的,基于这个性质,我们可以外推树的很多

python数据结构与算法 39 树的遍历

树的遍历 在学习完成树的基本结构以后,我们开始研究一些树的应用模式.访问树的全部节点,一般有三种模式,这些模式的不同之处,仅在于访问节点的顺序不同.我们把这种对节点的访问称为"遍历",这三种遍历模式叫做前序.中序和后序.下面我们对遍历模式作更仔细的定义,同时研究使用这延续模式的例子. 前序遍历 在前序遍历中,先访问根节点,然后用递归方式前序遍历它的左子树,最后递归方式前序遍历右子树. 中序遍历 在中序遍历中,先递归中序遍历左子树,然后访问根节点,最后递归中序遍历右子树. 后序遍历 在后

[算法]Huffman树(哈夫曼树)

[算法]Huffman树(哈夫曼树) 一.关于Huffman树 Huffman树(哈夫曼树)可以解决下述问题: 一颗\(n\)个叶节点的\(k\)叉树,第\(i\)个叶节点的权值为\(w_i\),现在欲求\(\sum w_i\times l_i\)的最小值,其中\(l_i\)表示第\(i\)个叶子节点到根结点的距离. 二.具体实现 为了保证\(\sum w_i\times l_i\)最小,我们应该保证权值越大的叶节点深度越小.可以看出,这是很简单的贪心思想. 特殊地,我们可以先从二叉Huffma