【系列】 點分治
阿新 • • 發佈:2018-12-22
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> 10View Code#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 }
但是樹形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