1. 程式人生 > >【系列】 點分治

【系列】 點分治

bzoj 2152 聰聰可可

題目大意:

求樹上邊權和為3的倍數的路徑的條數

思路:

點分治練習題 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstring>
 7 #include<vector>
 8 #include<stack>
 9 #include<queue>
10
#include<map> 11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i) 12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i) 13 #define ren for(int i=fst[x];i;i=nxt[i]) 14 #define Fill(x,t) memset(x,t,sizeof(x)) 15 #define ll long long 16 #define ull unsigned long long 17
#define inf 1000000000 18 #define MAXN 100100 19 #define MOD 998244353 20 using namespace std; 21 inline int read() 22 { 23 int x=0,f=1;char ch=getchar(); 24 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 25 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 26 return x*f; 27 } 28 int n,m,fst[MAXN],nxt[MAXN<<1
],to[MAXN<<1],val[MAXN<<1],cnt,res[MAXN]; 29 int q[MAXN],ans,sz[MAXN],mx[MAXN],rt,Mx,Sum,vis[MAXN],g[MAXN],len; 30 int gcd(int a,int b) {return !b?a:gcd(b,a%b);} 31 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 32 void getrt(int x,int pa) 33 { 34 sz[x]=1,mx[x]=0;ren if(to[i]!=pa&&!vis[to[i]]) {getrt(to[i],x);sz[x]+=sz[to[i]],mx[x]=max(mx[x],sz[to[i]]);} 35 mx[x]=max(mx[x],Sum-sz[x]);if(mx[x]<Mx) Mx=mx[x],rt=x; 36 } 37 void getdis(int x,int pa,int dep) {res[dep%3]++;ren if(to[i]!=pa&&!vis[to[i]]) getdis(to[i],x,dep+val[i]);} 38 int calc(int x,int dep) 39 { 40 Fill(res,0);getdis(x,0,dep);return res[0]*res[0]+res[1]*res[2]*2; 41 } 42 void div(int x) 43 { 44 vis[x]=1;ans+=calc(x,0); 45 ren if(!vis[to[i]]) {Sum=sz[to[i]],Mx=inf;ans-=calc(to[i],val[i]);getrt(to[i],0);div(rt);} 46 } 47 int main() 48 { 49 n=read();int a,b,c;rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c); 50 Sum=n,Mx=inf;getrt(1,0);div(1);a=n*n,b=gcd(a,ans);printf("%d/%d",ans/b,a/b); 51 }
View Code

但是樹形dp明顯更加優秀

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstring>
 7 #include<vector>
 8 #include<stack>
 9 #include<queue>
10 #include<map>
11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i)
12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i)
13 #define ren for(int i=fst[x];i;i=nxt[i])
14 #define Fill(x,t) memset(x,t,sizeof(x))
15 #define mns(a,b) ((a-b)%3+3)%3
16 #define ll long long
17 #define ull unsigned long long
18 #define inf 1000000000
19 #define MAXN 20010
20 #define MOD 998244353
21 using namespace std;
22 inline int read()
23 {
24     int x=0,f=1;char ch=getchar();
25     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
26     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
27     return x*f;
28 }
29 int n,m,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],val[MAXN<<1],cnt,dp[MAXN][3],ans;
30 int gcd(int a,int b) {return !b?a:gcd(b,a%b);}
31 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;}
32 void dfs(int x,int pa)
33 {
34     dp[x][0]=1;ren if(to[i]!=pa)
35     {
36         dfs(to[i],x);
37         ans+=dp[to[i]][mns(0,val[i])]*dp[x][0]+dp[x][1]*dp[to[i]][mns(2,val[i])]+dp[x][2]*dp[to[i]][mns(1,val[i])];
38         rep(j,0,2) dp[x][(j+val[i])%3]+=dp[to[i]][j];
39     }
40 }
41 int main()
42 {
43     n=read();int a,b,c;rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c);
44     dfs(1,0);(ans<<=1)+=n,a=n*n,b=gcd(a,ans);printf("%d/%d",ans/b,a/b);
45 }
View Code

 

luogu 3806 【模板】 點分治1

題目大意:

樹上Q次詢問 每次詢問路徑長度為k的路徑是否存在

思路:

為什麼那麼多$n^2$合併的程式碼啊喂

由於詢問數較小 跑Q次點分治即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstring>
 7 #include<vector>
 8 #include<stack>
 9 #include<queue>
10 #include<map>
11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i)
12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i)
13 #define ren for(int i=fst[x];i;i=nxt[i])
14 #define Fill(x,t) memset(x,t,sizeof(x))
15 #define ll long long
16 #define ull unsigned long long
17 #define inf 1000000000
18 #define MAXN 100100
19 #define MOD 998244353
20 using namespace std;
21 inline int read()
22 {
23     int x=0,f=1;char ch=getchar();
24     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
25     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
26     return x*f;
27 }
28 int n,m,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],val[MAXN<<1],cnt;
29 int q[MAXN],ans[MAXN],sz[MAXN],mx[MAXN],rt,Mx,Sum,vis[MAXN],g[MAXN],len;
30 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;}
31 void getrt(int x,int pa)
32 {
33     sz[x]=1,mx[x]=0;ren if(to[i]!=pa&&!vis[to[i]]) {getrt(to[i],x);sz[x]+=sz[to[i]],mx[x]=max(mx[x],sz[to[i]]);}
34     mx[x]=max(mx[x],Sum-sz[x]);if(mx[x]<Mx) Mx=mx[x],rt=x;
35 }
36 void getdis(int x,int pa,int dep) {g[++len]=dep;ren if(to[i]!=pa&&!vis[to[i]]) getdis(to[i],x,dep+val[i]);}
37 void calc(int x,int dep,int val)
38 {
39     int res=0,l,r;len=0;getdis(x,0,dep);sort(g+1,g+len+1);l=1,r=len;
40     rep(i,1,m)
41     {
42         while(l<=r) if(g[l]+g[r]>q[i]) r--;else res+=(g[l]+g[r]==q[i]),l++;
43         ans[i]+=res*val,res=0,l=1,r=len;
44     }
45 }
46 void div(int x)
47 {
48     vis[x]=1;calc(x,0,1);
49     ren if(!vis[to[i]]) {Sum=sz[to[i]],Mx=inf;calc(to[i],val[i],-1);getrt(to[i],0);div(rt);}
50 }
51 int main()
52 {
53     n=read(),m=read();int a,b,c;rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c);
54     rep(i,1,m) q[i]=read();Sum=n,Mx=inf;getrt(1,0);div(1);rep(i,1,m) puts(ans[i]?"AYE":"NAY");
55 }
View Code